source: extensions/AMetaData/amd_root.class.inc.php @ 5790

Last change on this file since 5790 was 5790, checked in by grum, 15 years ago

Add some GPS functionnalities

  • Property svn:executable set to *
File size: 11.9 KB
Line 
1<?php
2/*
3 * -----------------------------------------------------------------------------
4 * Plugin Name: Advanced MetaData
5 * -----------------------------------------------------------------------------
6 * Author     : Grum
7 *   email    : grum@piwigo.org
8 *   website  : http://photos.grum.fr
9 *   PWG user : http://forum.piwigo.org/profile.php?id=3706
10 *
11 *   << May the Little SpaceFrog be with you ! >>
12 *
13 * -----------------------------------------------------------------------------
14 *
15 * See main.inc.php for release information
16 *
17 * AMD_install : classe to manage plugin install
18 * ---------------------------------------------------------------------------
19 */
20
21if (!defined('PHPWG_ROOT_PATH')) { die('Hacking attempt!'); }
22
23include_once(PHPWG_PLUGINS_PATH.'grum_plugins_classes-2/common_plugin.class.inc.php');
24include_once(PHPWG_PLUGINS_PATH.'grum_plugins_classes-2/css.class.inc.php');
25
26include_once('amd_jpegmetadata.class.inc.php');
27include_once(JPEG_METADATA_DIR."Common/L10n.class.php");
28include_once(JPEG_METADATA_DIR."TagDefinitions/XmpTags.class.php");
29
30class AMD_root extends common_plugin
31{
32  protected $css;   //the css object
33  protected $jpegMD;
34
35  public function __construct($prefixeTable, $filelocation)
36  {
37    global $user;
38    $this->plugin_name="AMetaData";
39    $this->plugin_name_files="amd";
40    parent::__construct($prefixeTable, $filelocation);
41
42    $tableList=array('used_tags', 'images_tags', 'images', 'selected_tags', 'groups_names', 'groups');
43    $this->set_tables_list($tableList);
44
45    $this->css = new css(dirname($this->filelocation).'/'.$this->plugin_name_files.".css");
46    $this->jpegMD=new AMD_JpegMetaData();
47
48    if(isset($user['language']))
49    {
50      L10n::setLanguage($user['language']);
51    }
52  }
53
54  public function __destruct()
55  {
56    unset($this->jpegMD);
57    unset($this->css);
58    //parent::__destruct();
59  }
60
61
62  /* ---------------------------------------------------------------------------
63  common AIP & PIP functions
64  --------------------------------------------------------------------------- */
65
66  /* this function initialize var $my_config with default values */
67  public function init_config()
68  {
69    $this->my_config=array(
70      'amd_NumberOfItemsPerRequest' => 25,
71      'amd_GetListTags_OrderType' => "tag",
72      'amd_GetListTags_FilterType' => "magic",
73      'amd_GetListTags_ExcludeUnusedTag' => "y",
74      'amd_GetListTags_SelectedTagOnly' => "n",
75      'amd_GetListImages_OrderType' => "value",
76      'amd_FillDataBaseContinuously' => "y",
77      'amd_AllPicturesAreAnalyzed' => "n",
78    );
79  }
80
81  public function load_config()
82  {
83    parent::load_config();
84  }
85
86  public function init_events()
87  {
88    parent::init_events();
89
90
91    if(!isset($_REQUEST['ajaxfct']) and
92       $this->my_config['amd_FillDataBaseContinuously']=='y' and
93       $this->my_config['amd_AllPicturesAreAnalyzed']=='n')
94    {
95      /* do analyze for a random picture only if :
96       *  - config is set to fill database continuously
97       *  - we are not in an ajax call
98       */
99      add_event_handler('init', array(&$this, 'doRandomAnalyze'));
100    }
101  }
102
103
104  /**
105   * returns the number of pictures analyzed
106   *
107   * @return Integer
108   */
109  protected function getNumOfPictures()
110  {
111    $numOfPictures=0;
112    $sql="SELECT COUNT(imageId) FROM ".$this->tables['images']."
113            WHERE analyzed='y';";
114    $result=pwg_query($sql);
115    if($result)
116    {
117      while($row=mysql_fetch_row($result))
118      {
119        $numOfPictures=$row[0];
120      }
121    }
122    return($numOfPictures);
123  }
124
125
126  /**
127   * this function randomly choose a picture in the list of pictures not
128   * analyzed, and analyze it
129   *
130   */
131  public function doRandomAnalyze()
132  {
133    $sql="SELECT tai.imageId, ti.path FROM ".$this->tables['images']." tai
134            LEFT JOIN ".IMAGES_TABLE." ti ON tai.imageId = ti.id
135          WHERE tai.analyzed = 'n'
136          ORDER BY RAND() LIMIT 1;";
137    $result=pwg_query($sql);
138    if($result)
139    {
140      // $path = path of piwigo's on the server filesystem
141      $path=dirname(dirname(dirname(__FILE__)));
142
143      while($row=mysql_fetch_assoc($result))
144      {
145        $this->analyzeImageFile($path."/".$row['path'], $row['imageId']);
146      }
147
148      $this->makeStatsConsolidation();
149    }
150  }
151
152
153  /**
154   * this function analyze tags from a picture, and insert the result into the
155   * database
156   *
157   * NOTE : only implemented tags are analyzed and stored
158   *
159   * @param String $fileName : filename of picture to analyze
160   * @param Integer $imageId : id of image in piwigo's database
161   * @param Boolean $loaded  : default = false
162   *                            WARNING
163   *                            if $loaded is set to TRUE, the function assume
164   *                            that the metadata have been alreay loaded
165   *                            do not use the TRUE value if you are not sure
166   *                            of the consequences
167   */
168  protected function analyzeImageFile($fileName, $imageId, $loaded=false)
169  {
170    /*
171     * the JpegMetaData object is instancied in the constructor
172     */
173    if(!$loaded)
174    {
175      $this->jpegMD->load(
176        $fileName,
177        Array(
178          'filter' => AMD_JpegMetaData::TAGFILTER_IMPLEMENTED,
179          'optimizeIptcDateTime' => true,
180          'exif' => true,
181          'iptc' => true,
182          'xmp' => true
183        )
184      );
185    }
186
187    $sqlInsert="";
188    $massInsert=array();
189    $nbTags=0;
190    foreach($this->jpegMD->getTags() as $key => $val)
191    {
192      $value=$val->getLabel();
193
194      if($val->isTranslatable())
195        $translatable="y";
196      else
197        $translatable="n";
198
199      if($value instanceof DateTime)
200      {
201        $value=$value->format("Y-m-d H:i:s");
202      }
203      elseif(is_array($value))
204      {
205        /*
206         * array values are stored in a serialized string
207         */
208        $value=serialize($value);
209      }
210
211      $sql="SELECT numId FROM ".$this->tables['used_tags']." WHERE tagId = '$key'";
212
213      $result=pwg_query($sql);
214      if($result)
215      {
216        $numId=-1;
217        while($row=mysql_fetch_assoc($result))
218        {
219          $numId=$row['numId'];
220        }
221
222        if($numId>0)
223        {
224          $nbTags++;
225          if($sqlInsert!="") $sqlInsert.=", ";
226          $sqlInsert.="($imageId, '$numId', '".addslashes($value)."')";
227          $massInsert[]="('$imageId', '$numId', '".addslashes($value)."') ";
228        }
229      }
230    }
231
232    if(count($massInsert)>0)
233    {
234      $sql="REPLACE INTO ".$this->tables['images_tags']." (imageId, numId, value) VALUES ".implode(", ", $massInsert).";";
235      pwg_query($sql);
236    }
237    //mass_inserts($this->tables['images_tags'], array('imageId', 'numId', 'value'), $massInsert);
238
239    $sql="UPDATE ".$this->tables['images']."
240            SET analyzed = 'y', nbTags=".$nbTags."
241            WHERE imageId=$imageId;";
242    pwg_query($sql);
243
244
245    return("$imageId=$nbTags;");
246  }
247
248
249  /**
250   * do some consolidations on database to optimize other requests
251   *
252   */
253  protected function makeStatsConsolidation()
254  {
255    $sql="UPDATE ".$this->tables['used_tags']." ut,
256            (SELECT COUNT(imageId) AS nb, numId
257              FROM ".$this->tables['images_tags']."
258              GROUP BY numId) nb
259          SET ut.numOfImg = nb.nb
260          WHERE ut.numId = nb.numId;";
261    pwg_query($sql);
262
263
264    $sql="SELECT COUNT(imageId) AS nb
265          FROM ".$this->tables['images']."
266          WHERE analyzed = 'n';";
267    $result=pwg_query($sql);
268    if($result)
269    {
270      while($row=mysql_fetch_assoc($result))
271      {
272        $this->my_config['amd_AllPicturesAreAnalyzed']=($row['nb']==0)?'y':'n';
273      }
274
275    }
276    $this->save_config();
277  }
278
279
280  /**
281   * This function :
282   *  - convert arrays (stored as a serialized string) into human readable string
283   *  - translate value in user language (if value is translatable)
284   *
285   * @param String $value         : value to prepare
286   * @param Boolean $translatable : set to tru if the value can be translated in
287   *                                the user language
288   * @param String $separator     : separator for arrays items
289   * @return String               : the value prepared
290   */
291  protected function prepareValueForDisplay($value, $translatable=true, $separator=", ")
292  {
293    global $user;
294
295    if(preg_match('/^a:\d+:\{.*\}$/is', $value))
296    {
297      // $value is a serialized array
298      $tmp=unserialize($value);
299
300      if(count($tmp)==0)
301      {
302        return(L10n::get("Unknown"));
303      }
304
305      if(array_key_exists("computed", $tmp) and array_key_exists("detail", $tmp))
306      {
307        /* keys 'computed' and 'detail' are present
308         *
309         * assume this is the 'exif.exif.Flash' metadata and return the computed
310         * value only
311         */
312        return(L10n::get($tmp['computed']));
313      }
314      elseif(array_key_exists("type", $tmp) and array_key_exists("values", $tmp))
315      {
316        /* keys 'computed' and 'detail' are present
317         *
318         * assume this is an Xmp 'ALT', 'BAG' or 'SEQ' metadata and return the
319         * values only
320         */
321        if($tmp['type']=='alt')
322        {
323          /* 'ALT' structure
324           *
325           * ==> assuming the structure is used only for multi language values
326           *
327           * Array(
328           *    'type'   => 'ALT'
329           *    'values' =>
330           *        Array(
331           *            Array(
332           *                'type'  => Array(
333           *                            'name'  =>'xml:lang',
334           *                            'value' => ''           // language code
335           *                           )
336           *               'value' => ''         //value in the defined language
337           *            ),
338           *
339           *            Array(
340           *                // data2
341           *            ),
342           *
343           *        )
344           * )
345           */
346          $tmp=XmpTags::getAltValue($tmp, $user['language']);
347          if(trim($tmp)=="") $tmp="(".L10n::get("not defined").")";
348
349          return($tmp);
350        }
351        else
352        {
353          /* 'SEQ' or 'BAG' structure
354           *
355           *  Array(
356           *    'type'   => 'XXX',
357           *    'values' => Array(val1, val2, .., valN)
358           *  )
359           */
360          $tmp=$tmp['values'];
361
362          if(trim(implode("", $tmp))=="")
363          {
364            return("(".L10n::get("not defined").")");
365          }
366        }
367      }
368
369
370      foreach($tmp as $key=>$val)
371      {
372        if(is_array($val))
373        {
374          if($translatable)
375          {
376            foreach($val as $key2=>$val2)
377            {
378              $tmp[$key][$key2]=L10n::get($val2);
379            }
380            if(count($val)>0)
381            {
382              $tmp[$key]="[".implode($separator, $val)."]";
383            }
384            else
385            {
386              unset($tmp[$key]);
387            }
388          }
389        }
390        else
391        {
392          if($translatable)
393          {
394            $tmp[$key]=L10n::get($val);
395          }
396        }
397      }
398      return(implode($separator, $tmp));
399    }
400    elseif(preg_match('/\d{1,3}°\s\d{1,2}\'\s(\d{1,2}\.{0,1}\d{0,2}){0,1}.,\s(north|south|east|west)$/i', $value))
401    {
402      /* \d{1,3}°\s\d{1,2}\'\s(\d{1,2}\.{0,1}\d{0,2}){0,1}.
403       *
404       * keys 'coord' and 'card' are present
405       *
406       * assume this is a GPS coordinate
407       */
408        return(preg_replace(
409          Array('/, north$/i', '/, south$/i', '/, east$/i', '/, west$/i'),
410          Array(" ".L10n::get("North"), " ".L10n::get("South"), " ".L10n::get("East"), " ".L10n::get("West")),
411          $value)
412        );
413    }
414    else
415    {
416      if(trim($value)=="")
417      {
418        return("(".L10n::get("not defined").")");
419      }
420
421      if(strpos($value, "|")>0)
422      {
423        $value=explode("|", $value);
424        if($translatable)
425        {
426          foreach($value as $key=>$val)
427          {
428            $value[$key]=L10n::get($val);
429          }
430        }
431        return(implode("", $value));
432      }
433
434      if($translatable)
435      {
436        return(L10n::get($value));
437      }
438      return($value);
439    }
440  }
441
442} // amd_root  class
443
444
445
446?>
Note: See TracBrowser for help on using the repository browser.