source: extensions/ColorStat/cstat_aip.class.inc.php @ 15344

Last change on this file since 15344 was 15344, checked in by grum, 12 years ago

feature:2639 - Compatibility with Piwigo 2.4

  • Property svn:executable set to *
File size: 21.7 KB
Line 
1<?php
2/* -----------------------------------------------------------------------------
3  Plugin     : ColorStat
4  Author     : Grum
5    email    : grum@piwigo.org
6    website  : http://photos.grum.fr
7
8    << May the Little SpaceFrog be with you ! >>
9  ------------------------------------------------------------------------------
10  See main.inc.php for release information
11
12  CStat_AIP : classe to manage plugin admin pages
13
14  --------------------------------------------------------------------------- */
15
16if(!defined('PHPWG_ROOT_PATH')) die('Hacking attempt!');
17
18include_once('cstat_root.class.inc.php');
19include_once(PHPWG_PLUGINS_PATH.'GrumPluginClasses/classes/GPCTables.class.inc.php');
20include_once(PHPWG_PLUGINS_PATH.'GrumPluginClasses/classes/GPCTabSheet.class.inc.php');
21include_once(PHPWG_PLUGINS_PATH.'GrumPluginClasses/classes/GPCRequestBuilder.class.inc.php');
22include_once(PHPWG_ROOT_PATH.'admin/include/tabsheet.class.php');
23
24class CStat_AIP extends CStat_root
25{
26  protected $tabsheet;
27
28  public function __construct($prefixeTable, $filelocation)
29  {
30    parent::__construct($prefixeTable, $filelocation);
31    $this->checkRequest();
32
33    $this->loadConfig();
34    $this->initEvents();
35
36    $this->tabsheet = new tabsheet();
37    $this->tabsheet->add('database',
38                          l10n('cstat_database'),
39                          $this->getAdminLink()."-database");
40    $this->tabsheet->add('stat',
41                          l10n('cstat_stat'),
42                          $this->getAdminLink()."-stat");
43    $this->tabsheet->add('search',
44                          l10n('cstat_search'),
45                          $this->getAdminLink()."-search");
46    $this->tabsheet->add('config',
47                          l10n('cstat_config'),
48                          $this->getAdminLink()."-config");
49  }
50
51  public function __destruct()
52  {
53    unset($this->tabsheet);
54    parent::__destruct();
55  }
56
57  /*
58    initialize events call for the plugin
59  */
60  public function initEvents()
61  {
62    parent::initEvents();
63    if($_GET['tab']=='search')
64    {
65      // load request builder JS only on the search page
66      GPCRequestBuilder::loadJSandCSS();
67    }
68    add_event_handler('loc_end_page_header', array(&$this->css, 'applyCSS'));
69    GPCCss::applyGpcCss();
70  }
71
72  /*
73    display administration page
74  */
75  public function manage()
76  {
77    global $template;
78
79    $this->returnAjaxContent();
80
81    $template->set_filename('plugin_admin_content', dirname(__FILE__)."/admin/cstat_admin.tpl");
82
83    switch($_GET['tab'])
84    {
85      case 'database':
86        $this->displayDatabasePage();
87        break;
88      case 'stat':
89        $this->displayStatPage();
90        break;
91      case 'search':
92        $this->displaySearchPage();
93        break;
94      case 'config':
95        $this->displayConfigPage();
96        break;
97    }
98
99    $this->tabsheet->select($_GET['tab']);
100    $this->tabsheet->assign();
101    $selected_tab=$this->tabsheet->get_selected();
102    $template->assign($this->tabsheet->get_titlename(), "[".$selected_tab['caption']."]");
103
104    $template_plugin["CSTAT_VERSION"] = "<i>".$this->getPluginName()."</i> ".l10n('cstat_release').CSTAT_VERSION;
105
106    $template->assign('plugin', $template_plugin);
107    $template->assign_var_from_handle('ADMIN_CONTENT', 'plugin_admin_content');
108  }
109
110
111  /*
112    return ajax content
113  */
114  protected function returnAjaxContent()
115  {
116    global $ajax, $template;
117
118    if(isset($_REQUEST['ajaxfct']))
119    {
120      //$this->debug("AJAXFCT:".$_REQUEST['ajaxfct']);
121      $result="<p class='errors'>An error has occured</p>";
122      switch($_REQUEST['ajaxfct'])
123      {
124        case 'updateDatabaseGetStatus':
125          $result=$this->ajax_cstat_updateDatabaseGetStatus();
126          break;
127        case 'updateDatabaseGetList':
128          $result=$this->ajax_cstat_updateDatabaseGetList($_REQUEST['selectMode'], $_REQUEST['numOfItems']);
129          break;
130        case 'updateDatabaseDoAnalyze':
131          $result=$this->ajax_cstat_updateDatabaseDoAnalyze($_REQUEST['imagesList']);
132          break;
133        case 'updateDatabaseConsolidation':
134          $result=$this->ajax_cstat_updateDatabaseConsolidation();
135          break;
136        case 'showStatsGetListColors':
137          $result=$this->ajax_cstat_showStatsGetListColors($_REQUEST['orderType']);
138          break;
139        case 'doPpsBench':
140          $result=$this->ajax_cstat_ppsBench($_REQUEST['quality'], true);
141          break;
142      }
143      GPCAjax::returnResult($result);
144    }
145  }
146
147  /**
148   * check the $_REQUEST values and set default values
149   *
150   */
151  protected function checkRequest()
152  {
153    if(!isset($_GET['tab'])) $_GET['tab']='stat';
154
155
156    if(!($_GET['tab']=='database' or
157         $_GET['tab']=='stat' or
158         $_GET['tab']=='search' or
159         $_GET['tab']=='config')) $_GET['tab']='stat';
160
161
162    if(isset($_REQUEST['ajaxfct']))
163    {
164      if($_REQUEST['ajaxfct']=='updateDatabaseGetList')
165      {
166        if(!isset($_REQUEST['selectMode'])) $_REQUEST['selectMode']='caddieAdd';
167        if(!isset($_REQUEST['numOfItems'])) $_REQUEST['numOfItems']=$this->config['analyze_itemPerRequest'];
168
169        if(!($_REQUEST['selectMode']=='notAnalyzed' or
170             $_REQUEST['selectMode']=='all' or
171             $_REQUEST['selectMode']=='caddieAdd' or
172             $_REQUEST['selectMode']=='caddieReplace')) $_REQUEST['selectMode']='caddieAdd';
173
174        if($_REQUEST['numOfItems'] <=0 or $_REQUEST['numOfItems']>100) $_REQUEST['numOfItems']=10;
175      }
176
177
178      if($_REQUEST['ajaxfct']=='updateDatabaseDoAnalyze')
179      {
180        if(!isset($_REQUEST['imagesList'])) $_REQUEST['imagesList']='';
181      }
182
183      if($_REQUEST['ajaxfct']=='showStatsGetListColors')
184      {
185        if(!isset($_REQUEST['orderType'])) $_REQUEST['orderType']='img';
186
187        if(!($_REQUEST['orderType']=='color' or
188             $_REQUEST['orderType']=='img' or
189             $_REQUEST['orderType']=='pixels')) $_REQUEST['orderType']=='img';
190      }
191
192
193      if($_REQUEST['ajaxfct']=='doPpsBench')
194      {
195        if(!isset($_REQUEST['quality'])) $_REQUEST['quality']=8;
196        if($_REQUEST['quality']>50 or $_REQUEST['quality']<1) $_REQUEST['quality']=8;
197      }
198    }
199
200  }
201
202  /**
203   * display the database page
204   */
205  protected function displayDatabasePage()
206  {
207    global $template;
208
209    $template->set_filename('body_page',
210                dirname($this->getFileLocation()).'/admin/cstat_database.tpl');
211
212    pwg_query("INSERT INTO ".$this->tables['images']."
213                SELECT id, 'n', 0, 0, 0, 0, 0, 0, '', ''
214                  FROM ".IMAGES_TABLE."
215                  WHERE id NOT IN (SELECT image_id FROM ".$this->tables['images'].")");
216
217    $datas=Array(
218      'urlRequest' => $this->getAdminLink(),
219      'numberOfItemsPerRequest' => $this->config['analyze_itemPerRequest']
220    );
221    $template->assign('datas', $datas);
222    $template->assign_var_from_handle('CSTAT_BODY_PAGE', 'body_page');
223  } //displayDatabasePage
224
225  /**
226   * display the stat page
227   */
228  protected function displayStatPage()
229  {
230    global $template;
231
232    $template->set_filename('body_page',
233                dirname($this->getFileLocation()).'/admin/cstat_stat.tpl');
234
235    $colorTable=CStat_functions::getColorTableWithStat();
236
237
238    $datas=Array(
239      //'themeconf' => Array('name' => $template->get_themeconf('name')),
240      'colorTable' => CStat_functions::htmlColorTable(
241                        $colorTable,
242                        ($this->config['analyze_colorTable']=='small')?19:10,
243                        "",
244                        "color0px",
245                        "<br>"
246                      ),
247      'urlRequest' => $this->getAdminLink(),
248      'config_GetListColors_OrderType' => $this->config['display_stat_orderType'],
249    );
250    $template->assign('datas', $datas);
251    $template->assign_var_from_handle('CSTAT_BODY_PAGE', 'body_page');
252  } //displayStatPage
253
254
255  /**
256   * display search page
257   */
258  protected function displaySearchPage()
259  {
260    global $template, $lang;
261
262    $template->set_filename('body_page',
263                dirname($this->getFileLocation()).'/admin/cstat_search.tpl');
264
265    $template->assign('cstat_search_page', GPCRequestBuilder::displaySearchPage($this->getPluginName()));
266
267    $template->assign_var_from_handle('CSTAT_BODY_PAGE', 'body_page');
268  } //displaySearchPage
269
270
271  /**
272   * manage display of config page & save config
273   */
274  protected function displayConfigPage()
275  {
276    $tmpPct=$this->config['stat_minPct'];
277
278    if(!$this->adviser_abort())
279    {
280      if(isset($_POST['submit_save_config']))
281      {
282        foreach($this->config as $key => $val)
283        {
284          if(isset($_REQUEST['f_'.$key]))
285          {
286            $this->config[$key] = $_REQUEST['f_'.$key];
287          }
288        }
289        $this->displayResult(l10n('cstat_save_config'), $this->saveConfig());
290      }
291    }
292
293    if($tmpPct!=$this->config['stat_minPct'])
294    {
295      $this->updateDatabaseConsolidation();
296    }
297
298    $this->displayConfig();
299  }
300
301  /**
302   * display config page
303   */
304  protected function displayConfig()
305  {
306    global $template, $lang;
307
308    $configTabs=new GPCTabSheet('configTabsheet', $this->tabsheet->get_titlename(), 'tabsheet2 gcBorder', 'itab2');
309    $configTabs->add('database',
310                      l10n('cstat_database'),
311                      '', true, "displayConfig('database');");
312    $configTabs->add('statsearch',
313                      l10n('cstat_stat_and_search'),
314                      '', false, "displayConfig('statsearch');");
315    $configTabs->add('display',
316                      l10n('cstat_gallery_integration'),
317                      '', false, "displayConfig('display');");
318    $configTabs->assign();
319
320    $template->set_filename('body_page',
321                dirname($this->getFileLocation()).'/admin/cstat_config.tpl');
322
323    $nbPictures=0;
324    $sql="SELECT COUNT(image_id) FROM ".$this->tables['images'];
325    $result=pwg_query($sql);
326    if($result)
327    {
328      while($row=pwg_db_fetch_row($result))
329      {
330        $nbPictures=$row[0];
331      }
332    }
333
334
335    $datas=Array(
336      'nbPictures' => $nbPictures,
337      'pps' => $this->config['analyze_pps'],
338      'quality' => $this->config['analyze_ppsQuality'],
339      'qualityHighest' => 14000,
340      'qualityHigh' => 7500,
341      'qualityNormal' => 3500,
342      'qualityLow' => 1200,
343      'qualityLowest' => 600,
344      'urlRequest' => $this->getAdminLink(),
345      'minPct' => $this->config['stat_minPct'],
346      'showColors' => $this->config['display_gallery_showColors'],
347      'colorSize' => $this->config['display_gallery_colorSize'],
348    );
349
350    $template->assign('datas', $datas);
351
352    $template->assign_var_from_handle('CSTAT_BODY_PAGE', 'body_page');
353  } //displayConfig
354
355
356  /**
357   * manage adviser profile
358   * return true if user is adviser
359   */
360  protected function adviser_abort()
361  {
362    if(is_adviser())
363    {
364      $this->displayResult(l10n("cstat_adviser_not_allowed"), false);
365      return(true);
366    }
367    return(false);
368  }
369
370
371  /* ---------------------------------------------------------------------------
372    function to manage database manipulation
373  --------------------------------------------------------------------------- */
374  protected function analyzeImageFile($fileName, $imageId, $colorTable)
375  {
376    // set the picture to the 'try to analyze' statut
377    $sql="UPDATE ".$this->tables['images']." SET analyzed='t'
378          WHERE image_id=".$imageId.";";
379    pwg_query($sql);
380
381    $colors=ColorStat::getFileColors(
382      $fileName,
383      $colorTable,
384      Array(
385        'mode' => 'numAnalyzed',
386        'numColors' => 24,
387        'numAnalyzed' => $this->config['analyze_ppsQuality'],
388      )
389    );
390
391    if($colors!==false and
392       ColorStat::$fileColorsStat['colors']>0 and
393       ColorStat::$fileColorsStat['analyzed']>0)
394    {
395      $sql="UPDATE ".$this->tables['images']."
396              SET analyzed='y',
397                  num_colors='".ColorStat::$fileColorsStat['colors']."',
398                  num_pixels='".ColorStat::$fileColorsStat['pixels']."',
399                  analyzed_pixels='".ColorStat::$fileColorsStat['analyzed']."',
400                  pps='".ColorStat::$fileColorsStat['pps']."',
401                  time='".ColorStat::$fileColorsStat['time']."',
402                  quality='".ColorStat::$fileColorsStat['quality']."'
403            WHERE image_id=".$imageId.";";
404      pwg_query($sql);
405      $sql="";
406      foreach($colors as $key=>$val)
407      {
408        /*
409         * $key => RGB color #RRGGBB
410         * $val => Array (
411         *            'hsv' => Array ('H', 'S', 'V')
412         *            'num' => integer
413         *            'pct' => float
414         *          )
415         */
416
417        $sql.=(($sql=="")?"":", ")."
418              ('".$imageId."', '".$key."', ".$val['pct'].", ".$val['num'].")";
419      }
420      $sql="REPLACE INTO ".$this->tables['images_colors']."
421                VALUES ".$sql;
422      pwg_query($sql);
423
424      return($imageId.'='.ColorStat::$fileColorsStat['colors'].';');
425    }
426    else
427    {
428      return($imageId.'=KO;');
429    }
430  }
431
432
433  /**
434   * make consolidation for the color_table :
435   *  - count number of images using a color
436   *  - count number of pixels of a color
437   */
438  protected function updateDatabaseConsolidation()
439  {
440    $sql="UPDATE ".$this->tables['color_table']." cct
441          SET cct.num_images=0,
442              cct.num_pixels=0;";
443    pwg_query($sql);
444
445    $sql="UPDATE ".$this->tables['color_table']." cct,
446                 (SELECT color_id,
447                         count(image_id) AS num_images,
448                         sum(num_pixels) AS num_pixels
449                  FROM ".$this->tables['images_colors']."
450                  WHERE pct >= ".$this->config['stat_minPct']."
451                  GROUP BY color_id) cic
452          SET cct.num_images=cic.num_images,
453              cct.num_pixels=cic.num_pixels
454          WHERE cct.color_id=cic.color_id;";
455    pwg_query($sql);
456
457    $sql="UPDATE ".$this->tables['images']." pci
458          SET pci.colors = '',
459              pci.colors_pct = ''";
460    pwg_query($sql);
461
462    $sql="UPDATE ".$this->tables['images']." pci,
463          (SELECT image_id,
464                  GROUP_CONCAT(color_id ORDER BY pct DESC SEPARATOR ',') AS colors,
465                  GROUP_CONCAT(pct ORDER BY pct DESC SEPARATOR ',') AS colors_pct
466           FROM ".$this->tables['images_colors']."
467           WHERE pct >= ".$this->config['stat_minPct']."
468           GROUP BY image_id) pcic
469          SET pci.colors = pcic.colors,
470              pci.colors_pct = pcic.colors_pct
471          WHERE pci.image_id = pcic.image_id;";
472    pwg_query($sql);
473  }
474
475  /* ---------------------------------------------------------------------------
476    ajax functions
477  --------------------------------------------------------------------------- */
478
479  /**
480   * returns a list of formated string, separated with a semi-colon :
481   *  - number of current analyzed pictures
482   *  - number of pictures not analyzed + number of picture in error
483   *
484   * @return String
485   */
486  private function ajax_cstat_updateDatabaseGetStatus()
487  {
488    $numOfPictures=0;
489    $numOfPicturesNotAnalyzed=0;
490    $numOfPicturesInError=0;
491
492    $sql="SELECT COUNT(image_id), analyzed FROM ".$this->tables['images']."
493            GROUP BY analyzed;";
494    $result=pwg_query($sql);
495    if($result)
496    {
497      while($row=pwg_db_fetch_row($result))
498      {
499        switch($row[1])
500        {
501          case 'n': //no
502            $numOfPicturesNotAnalyzed=$row[0];
503            break;
504          case 'y': //yes
505            $numOfPictures=$row[0];
506            break;
507          case 't': //tried to be analyzed, but not finished
508            $numOfPicturesInError=$row[0];
509            break;
510        }
511      }
512    }
513
514    return(sprintf(l10n("cstat_numberOfAnalyzedPictures"), $numOfPictures).";".
515           sprintf(l10n("cstat_numberOfNotAnalyzedPictures"), $numOfPicturesNotAnalyzed).";".
516           sprintf(l10n("cstat_numberOfPicturesInError"), $numOfPicturesInError));
517  }
518
519
520  /**
521   * return a list of picture Id
522   *
523   * picture id are separated with a space " "
524   * picture id are grouped in blocks of 'NumberOfItemsPerRequest' items and
525   * are separated with a semi-colon ";"
526   *
527   * client side just have to split blocks, and transmit it to the server
528   *
529   * There is four mode to determine the pictures being analyzed :
530   *  - "all"           : analyze all the images (add & replace)
531   *  - "notAnalyzed"   : analyze only the images not yet analyzed (add)
532   *  - "caddieAdd"     : analyze all the images of the caddie (add)
533   *  - "caddieReplace" : analyze all the images of the caddie (add & replace)
534   *
535   * @param String $mode
536   * @param Integer $nbOfItems : number of items per request
537   * @return String : list of image id to be analyzed, separated with a space
538   *                      "23 78 4523 5670"
539   */
540  private function ajax_cstat_updateDatabaseGetList($mode, $nbOfItems)
541  {
542    global $user;
543
544    $returned="";
545
546    $sql="SELECT cit.image_id FROM ".$this->tables['images']." cit";
547    if($mode=="notAnalyzed")
548    {
549      $sql.=" WHERE cit.analyzed='n'";
550    }
551    elseif($mode=="caddieAdd" or $mode=="caddieReplace")
552    {
553      $sql.=" LEFT JOIN ".CADDIE_TABLE." ct ON cit.image_id = ct.element_id
554            WHERE ct.user_id = ".$user['id']." ";
555      if($mode=="caddieAdd") $sql.=" AND cit.analyzed='n'";
556    }
557
558    if($mode=="all" or $mode=="caddieReplace")
559    {
560      pwg_query("UPDATE ".$this->tables['images']."
561                  SET analyzed='n',
562                      num_colors=0,
563                      num_pixels=0,
564                      analyzed_pixels=0,
565                      pps=0,
566                      time=0,
567                      quality=0
568                  WHERE analyzed<>'t'");
569      pwg_query("DELETE FROM ".$this->tables['images_colors']);
570      pwg_query("UPDATE ".$this->tables['color_table']."
571                 SET num_pixels=0, num_images=0;");
572    }
573
574    $result=pwg_query($sql);
575    if($result)
576    {
577      $i=0;
578      while($row=pwg_db_fetch_row($result))
579      {
580        $returned.=$row[0];
581        $i++;
582        if($i>=$nbOfItems)
583        {
584          $returned.=";";
585          $i=0;
586        }
587        else
588        {
589          $returned.=" ";
590        }
591      }
592    }
593    return(trim($returned).";");
594  }
595
596
597
598  /**
599   * extract metadata from images
600   *
601   * @param String $imageList : list of image id to be analyzed, separated with
602   *                            a space
603   *                                "23 78 4523 5670"
604   * @return String : list of the analyzed pictures, with number of colors found
605   *                  for each picture
606   *                    "23=0;78=66;4523=33;5670=91;"
607   */
608  private function ajax_cstat_updateDatabaseDoAnalyze($imagesList)
609  {
610    $list=explode(" ", trim($imagesList));
611
612    $returned="";
613
614    if(count($list)>0 and trim($imagesList)!='')
615    {
616      // $path = path of piwigo's on the server filesystem
617      $path=dirname(dirname(dirname(__FILE__)));
618
619      $sql="SELECT id, path FROM ".IMAGES_TABLE." WHERE id IN (".implode(", ", $list).")";
620      $result=pwg_query($sql);
621      if($result)
622      {
623        $colorTable=ColorStat::getColorTable(
624          CStat_root::$colorTableSize[$this->config['analyze_colorTable']][0],
625          CStat_root::$colorTableSize[$this->config['analyze_colorTable']][1]
626        );
627
628        while($row=pwg_db_fetch_assoc($result))
629        {
630          /*
631           * in some case (in a combination of some pictures), when there is too
632           * much pictures to analyze in the same request, a fatal error occurs
633           * with the message : "Allowed memory size of XXXXX bytes exhausted"
634           *
635           *
636           * tracking memory leak is not easy... :-(
637           *
638           */
639          //echo "analyzing:".$row['id']."\n";
640          //$mem1=memory_get_usage();
641          //echo "memory before analyze:".$mem1."\n";
642          $returned.=$this->analyzeImageFile($path."/".$row['path'], $row['id'], $colorTable);
643          //echo $returned."\n";
644          //$mem2=memory_get_usage();
645          //echo "memory after analyze:".$mem2." (".($mem2-$mem1).")\n";
646        }
647      }
648    }
649    return($returned);
650  }
651
652
653  /**
654   * make consolidation for the color_table :
655   *  - count number of images using a color
656   *  - count number of pixels of a color
657   */
658  private function ajax_cstat_updateDatabaseConsolidation()
659  {
660    $this->updateDatabaseConsolidation();
661    return("ok");
662  }
663
664
665
666  /**
667   * return a formatted <table> (using the template "cstat_stat_show_iListColors")
668   * of used tag with, for each tag, the number and the percentage of pictures
669   * where the tag was found
670   *
671   * @param String $orderType : order for the list (by color 'color' or by number
672   *                            of pictures 'img' or by number of pixels 'pixels')
673   * @return String
674   */
675  private function ajax_cstat_showStatsGetListColors($orderType)
676  {
677    global $template;
678
679    $this->config['display_stat_orderType'] = $orderType;
680    $this->saveConfig();
681
682    $local_tpl = new Template(CSTAT_PATH."admin/", "");
683    $local_tpl->set_filename('body_page',
684                  dirname($this->getFileLocation()).'/admin/cstat_stat_show_iListColors.tpl');
685
686    $generalStats=CStat_functions::getGeneralStats();
687
688    $sql="SELECT color_id, num_images, num_pixels
689          FROM ".$this->tables['color_table']."
690          WHERE num_images > 0 ";
691    if($orderType=='color')
692    {
693      $sql.=" ORDER BY hue ASC, saturation ASC, value DESC";
694    }
695    elseif($orderType=='img')
696    {
697      $sql.=" ORDER BY num_images DESC, num_pixels DESC ";
698    }
699    elseif($orderType=='pixels')
700    {
701      $sql.=" ORDER BY num_pixels DESC, num_images DESC ";
702    }
703
704    $datas=Array();
705    $result=pwg_query($sql);
706    if($result)
707    {
708      while($row=pwg_db_fetch_assoc($result))
709      {
710        $row['pct_images']=sprintf('%.2f', round(100*$row['num_images']/$generalStats['nbImages'],2));
711        $row['pct_pixels']=sprintf('%.2f', round(100*$row['num_pixels']/$generalStats['pixelsAnalyzedSum'],2));
712        $datas[]=$row;
713      }
714    }
715
716    $local_tpl->assign('themeconf', Array('name' => $template->get_themeconf('name')));
717    $local_tpl->assign('datas', $datas);
718
719    return($local_tpl->parse('body_page', true));
720  }
721
722} //class
723
724
725?>
Note: See TracBrowser for help on using the repository browser.