source: extensions/EStat/estat_root.class.inc.php @ 17737

Revision 17737, 16.9 KB checked in by grum, 7 years ago (diff)

First commit for EStat files

  • Property svn:executable set to *
Line 
1<?php
2/* -----------------------------------------------------------------------------
3  Plugin     : EStat
4  Author     : Grum
5    email    : grum@piwigo.org
6    website  : http://www.grum.fr
7
8    << May the Little SpaceFrog be with you ! >>
9  ------------------------------------------------------------------------------
10  See main.inc.php for release information
11
12  EStat_root : common classe for admin and public classes
13
14  --------------------------------------------------------------------------- */
15  include_once(PHPWG_PLUGINS_PATH.'GrumPluginClasses/classes/CommonPlugin.class.inc.php');
16  include_once(ESTAT_LIB.'statDB.class.inc.php');
17  include_once(ESTAT_LIB.'statDBGlobal.class.inc.php');
18  include_once(ESTAT_LIB.'statDBMonth.class.inc.php');
19  include_once(ESTAT_LIB.'statDBCountry.class.inc.php');
20
21  class EStat_root extends CommonPlugin
22  {
23    const DATA_DIRECTORY='plugins/EStat/data/';
24    const EXPORT_DIRECTORY='plugins/EStat/export/';
25    const FILE_MONTH='ES-M';
26    const FILE_GLOBAL='ES-G';
27    const FILE_COUNTRY='ES-IPCountry';
28
29    public $countryCodes=array(
30              'AD','AE','AF','AG','AI','AL','AM','AO','AQ','AR','AS','AT','AU','AW','AX','AZ',
31              'BA','BB','BD','BE','BF','BG','BH','BI','BJ','BL','BM','BN','BO','BQ','BR','BS','BT','BV','BW','BY','BZ',
32              'CA','CC','CD','CF','CG','CH','CI','CK','CL','CM','CN','CO','CR','CU','CV','CW','CX','CY','CZ',
33              'DE','DJ','DK','DM','DO','DZ',
34              'EC','EE','EG','EH','ER','ES','ET',
35              'FI','FJ','FK','FM','FO','FR',
36              'GA','GB','GD','GE','GF','GG','GH','GI','GL','GM','GN','GP','GQ','GR','GS','GT','GU','GW','GY',
37              'HK','HM','HN','HR','HT','HU',
38              'ID','IE','IL','IM','IN','IO','IQ','IR','IS','IT',
39              'JE','JM','JO','JP',
40              'KE','KG','KH','KI','KM','KN','KP','KR','KW','KY','KZ',
41              'LA','LB','LC','LI','LK','LR','LS','LT','LU','LV','LY',
42              'MA','MC','MD','ME','MF','MG','MH','MK','ML','MM','MN','MO','MP','MQ','MR','MS','MT','MU','MV','MW','MX','MY','MZ',
43              'NA','NC','NE','NF','NG','NI','NL','NO','NP','NR','NU','NZ',
44              'OM',
45              'PA','PE','PF','PG','PH','PK','PL','PM','PN','PR','PS','PT','PW','PY',
46              'QA',
47              'RE','RO','RS','RU','RW',
48              'SA','SB','SC','SD','SE','SG','SH','SI','SJ','SK','SL','SM','SN','SO','SR','SS','ST','SV','SX','SY','SZ',
49              'TC','TD','TF','TG','TH','TJ','TK','TL','TM','TN','TO','TR','TT','TV','TW','TZ',
50              'UA','UG','UM','US','UY','UZ',
51              'VA','VC','VE','VG','VI','VN','VU',
52              'WF','WS',
53              'XA',
54              'YE','YT',
55              'ZA','ZM','ZW'
56            );
57
58    protected $fileStatDir='';
59
60    public function __construct($prefixeTable, $filelocation)
61    {
62      $this->setPluginName('EStat');
63      $this->setPluginNameFiles("estat");
64      parent::__construct($prefixeTable, $filelocation);
65      $this->section_name=$this->getPluginNameFiles();
66      $this->fileStatDir=GPCCore::getPiwigoSystemPath().'/'.PWG_LOCAL_DIR.self::DATA_DIRECTORY;
67    }
68
69    /**
70     * initialize default values
71     */
72    public function initConfig()
73    {
74      //global $user;
75      $this->config=array(
76        'plugin.newInstall' => 'y',
77        'plugin.active' => 'n',
78        'plugin.historyImported' => 'n',
79        'plugin.ipCountryBuild' => 'n',
80
81        'build.delay' => '+24hours',     // delay between 2 consolidation
82        'build.start' => '2:30:00',      // consolidation can be done from
83        'build.end' => '6:30:00',        // build.start hour to build.end hour
84        'compress.public' => 'n',        // compress file in public session
85        'compress.method' => 'none',     // none, gz
86
87        'global.itemPerPage' => 250,
88
89        'logs.reverseDNS' => 'n',
90        'logs.ipCountry' => 'y'
91      );
92    }
93
94    /**
95     * return admin link
96     * @param String $mode: if equal 'ajax' return url for ajax call
97     * @return String: url
98     */
99    public function getAdminLink($mode='')
100    {
101      switch($mode)
102      {
103        case 'ajax':
104          return('plugins/'.basename(dirname($this->getFileLocation())).'/estat_ajax.php');
105          break;
106        case 'ajaxExport':
107          return('plugins/'.basename(dirname($this->getFileLocation())).'/estat_ajax_export.php');
108          break;
109        default:
110          return(parent::getAdminLink());
111          break;
112      }
113   }
114
115
116
117    /**
118    * checks files that need to be consolidated
119    * pack them if needed
120    *
121    * @param Boolean $force: force consolidation if true, otherwise let system to determinate if needed
122    * @param Boolean $pack: pack files if needed
123    * @return Boolean: true if at least one consolidation was applied, otherwise false
124    */
125    protected function checkBuildStatPeriod($force=false, $pack=true)
126    {
127      $build=false;
128      $currentTime=date('H:i:s');
129      $currentDateTime=strtotime($this->config['build.delay']);
130      $currentYearMonth=date('Ym');
131
132
133      $dbStatG=new StatDBGlobal($this->fileStatDir, self::FILE_GLOBAL);
134      $dbStatG->open(ASDF_OPEN_WRITE);
135
136      // check if current period exist in global file
137      $dbStatG->checkFilePeriod(substr($currentYearMonth, 0,4), substr($currentYearMonth,4,2));
138
139      // get list of files to build
140      $fileList=$dbStatG->getFilesList(ASDF_EXIST_PACKED|ASDF_EXIST_UNPACKED, ASDF_BUILD_MISSING);
141
142      foreach($fileList as $file)
143      {
144        $file['month']=sprintf('%02d', $file['month']);
145
146        if($force or
147          ($currentDateTime>=$file['lastBuilt'] and
148            $currentTime>=$this->config['build.start'] and
149            $currentTime<=$this->config['build.end']))
150        {
151          if($dbStatG->buildStatPeriod($this->fileStatDir, self::FILE_MONTH, $file['year'], $file['month']))
152            $build=true;
153
154          if($pack and  //pack only if asked
155             $file['packed']==0 and //packed size=0 -> not packed
156             $file['year'].$file['month']!=$currentYearMonth) //don't pack current file!
157          {
158            $dbStatM=new StatDBMonth($this->fileStatDir, self::FILE_MONTH, $file['year'], $file['month']);
159            if($dbStatM->pack())
160            {
161              $packedFileName=$dbStatM->getFileName(ASDF_EXIST_PACKED, true);
162              if($packedFileName!='')
163                $dbStatG->updatePackedSize($file['year'], $file['month'], filesize($packedFileName));
164              $dbStatM->delete(ASDF_DELETE_UNPACKED);
165            }
166          }
167        }
168      }
169
170      $dbStatG->close();
171
172      return($build);
173    }
174
175
176    /**
177     * Returns the needed informations to process the data migration
178     *
179     * Returned information is an array:
180     * array(
181     *  'nbLogs'  => number of logs
182     *  'idMax'   => maximum id in HISTORY table
183     *  'idMin'   => minimum id in HISTORY table
184     *  'dateMax' => maximum date in HISTORY table
185     *  'dateMin' => minimum date in HISTORY table
186     *  'periods' => array of periods to process
187     *                 key=period (yyyy-mm)
188     *                 value=number of events for the period
189     *
190     * @return Array
191     */
192    protected function getPiwigoHistoryInfo()
193    {
194      $data=array(
195        'nbLogs' => 0,
196        'idMax' => 0,
197        'idMin' => 0,
198        'dateMax' => '',
199        'dateMin' => '',
200        'periods' => array()
201        );
202
203      $sql="SELECT COUNT(id), MIN(id), MAX(id), MIN(`date`), MAX(`date`)
204            FROM ".HISTORY_TABLE;
205      $result=pwg_query($sql);
206      if($result)
207      {
208        if($tmp=pwg_db_fetch_row($result))
209        {
210          $data['nbLogs']=$tmp[0];
211          $data['idMin']=$tmp[1];
212          $data['idMax']=$tmp[2];
213          $data['dateMin']=$tmp[3];
214          $data['dateMax']=$tmp[4];
215
216          $sql="SELECT COUNT(id) AS nbEvents, YEAR(`date`) AS periodYear, MONTH(`date`) AS periodMonth
217                FROM ".HISTORY_TABLE."
218                GROUP BY periodYear, periodMonth
219                ORDER BY periodYear, periodMonth;";
220
221          $result=pwg_query($sql);
222          if($result)
223          {
224            while($row=pwg_db_fetch_assoc($result))
225            {
226              $data['periods'][sprintf('%04d-%02d', $row['periodYear'], $row['periodMonth'])]=$row['nbEvents'];
227            }
228          }
229        }
230      }
231      return($data);
232    }
233
234
235    /*
236     * -------------------------------------------------------------------------
237     * -- functions used by the ajax classes
238     * -------------------------------------------------------------------------
239     */
240
241
242
243    /**
244     * generic function to consolidate a list of Id in a list with distinct Id
245     *
246     * the &$table parameter is an array with predefined keys     *
247     *
248     * @param Array &$table : the table were to put result
249     * @param String $key : the key (of the table) where result have to be put
250     * @param String $sql : SQL request to produce the id list
251     */
252    protected function prepareIdList(&$table, $key, $sql)
253    {
254      $result=pwg_query($sql);
255      if($result)
256      {
257        while($row=pwg_db_fetch_assoc($result))
258        {
259          $table[$key][$row['id']]=$row;
260        }
261      }
262    }
263
264    /**
265     * generic function to prepare a list of unique IP adress with the following
266     * informations:
267     *  - reverse DNS (if asked)
268     *  - country
269     *  returned keys are IP adress, associated value is an array
270     *    ip => array('rdns' => reverseDNS, 'country' => country_code)
271     *
272     * @param Array &$table : the table were to put result
273     * @param Array $items : array of IP adress
274     * @param Boolean $force : if true, force to produce the reversed DNS address
275     */
276    protected function getIpInfos(&$table, $items, $force=false)
277    {
278      $dbCountry=new StatDBCountry($this->fileStatDir, self::FILE_COUNTRY);
279      $dbCountry->open(ASDF_OPEN_READ);
280
281      foreach($items as $IP)
282      {
283        $table['IPadress'][$IP]=array(
284          'rdns' => '',
285          'country' => $dbCountry->getIpCountry($IP, false)
286        );
287
288        if($force or $this->config['logs.reverseDNS']=='y')
289          $table['IPadress'][$IP]=gethostbyaddr($IP);
290      }
291      $dbCountry->close();
292    }
293
294
295
296    /**
297     * return the label associated to the id, or a default value if nothing is
298     * found
299     *
300     * @param Array $table: array of label
301     * @param string $key: type of id
302     * @param string $id: id for which the label have to be retrieved
303     * @param string $default: default value to return if no label found
304     * @return string: label
305     */
306    protected function getId($table, $key, $id, $default='', $field='name')
307    {
308      if(is_array($id))
309      {
310        $tmp=array();
311        foreach($id as $val)
312        {
313          $tmp[]=$this->getId($table, $key, $val, $default, $field);
314        }
315        return(implode(',', $tmp));
316      }
317      elseif(isset($table[$key]) and isset($table[$key][$id]) and isset($table[$key][$id][$field]))
318      {
319        return($table[$key][$id][$field]);
320      }
321      else return($default);
322    }
323
324
325    /**
326     * build a filter of category id; for each given id, the childrens are selected
327     * too
328     *
329     * @param Array $catId: category id list
330     * @return Array
331     */
332    protected function buildCatIdFilter($catId)
333    {
334      $returned=array();
335
336      if(!is_array($catId)) return($returned);
337
338      $where=array();
339      foreach($catId as $id)
340      {
341        $where[]="FIND_IN_SET('$id', uppercats)";
342      }
343      $sql="SELECT DISTINCT id
344            FROM ".CATEGORIES_TABLE."
345            WHERE ".implode(' OR ', $where);
346      $tmpResult=pwg_query($sql);
347      if($tmpResult)
348      {
349        $tmp=array();
350        while($row=pwg_db_fetch_row($tmpResult))
351        {
352          $tmp[]=$row[0];
353        }
354        $returned=array('operator' => 'in', 'value' => $tmp);
355      }
356      return($returned);
357    }
358
359
360
361
362  } //class
363
364
365
366/*
367 * ------------------------------------------------------------------------------------------------
368 * -- classes used for ajax                                                                      --
369 * ------------------------------------------------------------------------------------------------
370 */
371
372
373  /**
374   * this class is used to build list of unique Id
375   */
376  class EStat_IdList
377  {
378    protected $listItems=array();
379
380    public function __construct($items)
381    {
382      if(is_array($items)) $this->init($items);
383    }
384
385    public function __destruct()
386    {
387    }
388
389    /**
390     * initialize the names of identifiers pool
391     * for example, init(array('album', 'image')) to declare a pool for 'album' id
392     * and another pool for 'image' id
393     *
394     * @param Array $items: array of names
395     */
396    public function init($items)
397    {
398      $this->listItems=array();
399      foreach($items as $item)
400      {
401        $this->listItems[$item]=array();
402      }
403    }
404
405    /**
406     * add items in the pool
407     *
408     * $items is an array of (key => value)
409     * for example:
410     *  addItems(
411     *    'album' => 1,
412     *    'album' => 2,
413     *    'album' => 1,
414     *    'image' => 236
415     *  );
416     *
417     * will be (internaly) stored as
418     *   listItems(
419     *     'album' => array(1,2),
420     *     'image' => array(236)
421     *   );
422     *
423     * @param Array $items
424     */
425    public function addItems($items)
426    {
427      if(is_array($items))
428      {
429        foreach($items as $key => $item)
430        {
431          $this->add($key, $item);
432        }
433      }
434    }
435
436    /**
437     * return the associated list of item for an identifier
438     * for example:
439     *   getItems('album')
440     * will return:
441     *   array(1,2)
442     *
443     * @param Array $item: identifier
444     * @return Array
445     */
446    public function getItems($item)
447    {
448      if(isset($this->listItems[$item]))
449      {
450        return(array_keys($this->listItems[$item]));
451      }
452      else
453      {
454        return(array());
455      }
456    }
457
458    /**
459     * add an item for an identifier
460     *
461     * @param string $key: identifier
462     * @param string $item: value to add
463     */
464    private function add($key, $item)
465    {
466      if(is_array($item))
467      {
468        foreach($item as $val)
469        {
470          $this->add($key, $val);
471        }
472        return(true);
473      }
474
475      if($item!='' and isset($this->listItems[$key]) and !isset($this->listItems[$key][$item]))
476      {
477        $this->listItems[$key][$item]='';
478      }
479    }
480  } // class EStat_IdList
481
482
483
484
485
486
487
488
489  class ReverseIP
490  {
491    protected $ipList=array();
492    protected $ipFile='';
493
494    /**
495     * add an IP adress in the list, by default there's no browser type set
496     * for the IP adress
497     * @param String $IP: IP adress
498     * @param Integer $type: if not set, value is defined automatically
499     */
500    public function addIP($IP, $type=null)
501    {
502      if(!isset($this->ipList[$IP]))
503        $this->ipList[$IP]=UA_BROWSER_TYPE_UNKNOWN; //$this->fromReverseDNS(gethostbyaddr($IP));
504    }
505
506    /**
507     * return IP browser type
508     * @param String $IP: IP adress
509     * @return Integer: -1 if IP adress not exists
510     */
511    public function getIP($IP)
512    {
513      if(!isset($this->ipList[$IP])) return(-1);
514      return($this->ipList[$IP]);
515    }
516
517    /**
518     * set IP type
519     *
520     * @param String $IP: IP adress
521     * @param Integer $type: type of browser
522     * @return Integer: type set, -1 if an error occurs
523     */
524    public function setIP($IP, $type)
525    {
526      if(!isset($this->ipList[$IP])) return(-1);
527      if($this->ipList[$IP]==-1) $this->ipList[$IP]=$type;
528      return($this->ipList[$IP]);
529    }
530
531    /**
532     * delete the temporary ip file
533     */
534    public function deleteIPFile()
535    {
536      if(file_exists($this->ipFile))
537        unlink($this->ipFile);
538    }
539
540    /**
541     * load an IP file in memory
542     *
543     * @param String $file: file to load
544     * @return Boolean: true or false
545     */
546    public function loadIPFile($file)
547    {
548      $this->ipFile=$file;
549      if(!file_exists($file)) return(false);
550      $this->ipList=array();
551
552      $fHandle=fopen($this->ipFile, 'r');
553      if($fHandle)
554      {
555        $tmp=fread($fHandle, filesize($this->ipFile));
556        fclose($fHandle);
557        $this->ipList=unserialize($tmp);
558        return(true);
559      }
560      return(false);
561    }
562
563    /**
564     * save IP list on a file
565     *
566     * @param String $file: file to load
567     * @return Boolean: true or false
568     */
569    public function saveIPFile()
570    {
571      if($this->ipFile=='') return(false);
572      $fHandle=fopen($this->ipFile, 'w');
573      if($fHandle)
574      {
575        fwrite($fHandle, serialize($this->ipList));
576        fclose($fHandle);
577        return(true);
578      }
579      return(false);
580    }
581
582    /**
583     * try to know from a reversed DNS adress if visitor is a crawler or not
584     *
585     * @param String $revDNS: a reversed DNS IP address
586     * @return Integer: UA_BROWSER_TYPE_UNKNOWN or UA_BROWSER_TYPE_CRAWLER
587     */
588    public function fromReverseDNS($revDNS)
589    {
590      $returned=UA_BROWSER_TYPE_UNKNOWN;
591
592      if(preg_match('/\s*([a-z]*(?:bot|spyder|crawl|crawler|spider)[a-z]*)/i', $revDNS))
593        $returned=UA_BROWSER_TYPE_CRAWLER;
594
595      return($returned);
596    }
597  } // class ReverseIP
598
599
600
601?>
Note: See TracBrowser for help on using the repository browser.