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

Last change on this file since 5961 was 5961, checked in by grum, 10 years ago

Add plugin files

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