source: extensions/EStat/lib/statDB.class.inc.php @ 17737

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

First commit for EStat files

  • Property svn:executable set to *
File size: 29.3 KB
Line 
1<?php
2
3include_once(PHPWG_PLUGINS_PATH.'GrumPluginClasses/classes/GPCCompress.class.inc.php');
4
5define('ASDF_DELETE_PACKED',   0x01);
6define('ASDF_DELETE_UNPACKED', 0x02);
7
8define('ASDF_EXIST_NO',       0x00);
9define('ASDF_EXIST_PACKED',   0x01);
10define('ASDF_EXIST_UNPACKED', 0x02);
11define('ASDF_EXIST_ALL', ASDF_EXIST_PACKED|ASDF_EXIST_UNPACKED);
12
13define('ASDF_FILE_EXT', '.db');
14define('ASDF_FILE_EXT_ZIP', ASDF_FILE_EXT.'.gz');
15define('ASDF_FILE_ROOT_MONTH', 'M');
16define('ASDF_FILE_ROOT_GLOBAL', 'G');
17
18
19define('ASDF_DB_INFO',      0x01);
20define('ASDF_DB_NUM_ROWS',  0x02);
21define('ASDF_DB_LIST',  0x03);
22
23define('ASDF_DB_TYPE_TABLE', 0x01);
24define('ASDF_DB_TYPE_INDEX', 0x02);
25define('ASDF_DB_TYPE_TRIGGER', 0x03);
26define('ASDF_DB_TYPE_LOG', 0x04);
27define('ASDF_DB_TYPE_NFO', 0x05);
28
29define('ASDF_TRANSAC_COMMIT', 0x01);
30define('ASDF_TRANSAC_ROLLBACK', 0x02);
31
32define('ASDF_GET_ROWS', 0x01);
33define('ASDF_GET_COUNT', 0x02);
34
35define('ASDF_BUILD_DONE', 0x01);
36define('ASDF_BUILD_MISSING', 0x02);
37define('ASDF_BUILD_ALL', ASDF_BUILD_DONE|ASDF_BUILD_MISSING);
38
39define('ASDF_OPEN_READ', 0x01);
40define('ASDF_OPEN_WRITE', 0x02);
41
42define('ASDF_CLOSE_DO_NOTHING', 0x00);
43define('ASDF_CLOSE_DO_PACK', 0x01);
44define('ASDF_CLOSE_DO_DELETE', 0x02);
45
46/**
47 * main class for SQLite files managment
48 */
49class StatDB
50{
51  protected $fileRootName='';
52  protected $fileDir='';
53  protected $fileName='';
54  protected $dbHandle=null;
55  protected $transacOpen=false;
56  protected $ipCountryFile='';
57
58  private $deleteUnpackedWhenClose=ASDF_CLOSE_DO_NOTHING;
59
60  /**
61   * constructor
62   *
63   * @param String $directory: directory where the sqlite file is saved
64   * @param String $fileName: file name (without extension)
65   */
66  public function __construct($directory='', $fileName='')
67  {
68    $this->setDirectory($directory);
69    $this->setFileName($fileName);
70  }
71
72  public function __destruct()
73  {
74   $this->close();
75  }
76
77
78  /**
79   * return informations about the current data file
80   *
81   * @return Array
82   */
83  public function getInfo()
84  {
85    $returned=array(
86      'dirName'       => $this->fileDir,
87      'fileName'      => $this->fileName,
88      'fileExist'     => $this->fileExist(),
89      'open'          => ($this->dbHandle==null)?false:true,
90      'unpackedFile'  => array(
91                            'fileName' => $this->getFileName(ASDF_EXIST_UNPACKED),
92                            'fileSize' => ($this->getFileName(ASDF_EXIST_UNPACKED, true)!='')?filesize($this->getFileName(ASDF_EXIST_UNPACKED)):0
93                          ),
94      'packedFile'    => array(
95                            'fileName' => $this->getFileName(ASDF_EXIST_PACKED),
96                            'fileSize' => ($this->getFileName(ASDF_EXIST_PACKED, true)!='')?filesize($this->getFileName(ASDF_EXIST_PACKED)):0
97                          )
98    );
99
100    if($this->dbHandle!=null)
101    {
102      $tables=$this->getDBInfo(ASDF_DB_TYPE_TABLE, null, ASDF_DB_LIST);
103
104      $returned['nbRecords']=array();
105      foreach($tables as $table)
106      {
107        $returned['nbRecords'][$table] = $this->getDBInfo(ASDF_DB_TYPE_TABLE, $table, ASDF_DB_NUM_ROWS);
108      }
109      $returned['db']=array(
110                        'integrity'    => $this->getPragma('integrity_check'),
111                        'pages'        => $this->getPragma('page_count'),
112                        'pageSize'     => $this->getPragma('page_size'),
113                        'unusedPages'  => $this->getPragma('freelist_count'),
114                        'version(s)'   => $this->getPragma('schema_version'),
115                        'version(u)'   => $this->getPragma('user_version')
116                      );
117
118
119      $logs=$this->getDBInfo(ASDF_DB_TYPE_LOG, null, null);
120      $returned['log']=array();
121      foreach($logs as $log)
122      {
123        $returned['log'][$log['key']] = $log['value'];
124      }
125
126
127      $nfos=$this->getDBInfo(ASDF_DB_TYPE_NFO, null, null);
128      $returned['nfo']=array();
129      foreach($nfos as $nfo)
130      {
131        $returned['nfo'][$nfo['key']] = $nfo['value'];
132      }
133
134    }
135    return($returned);
136  }
137
138  /**
139   * set the directory
140   *
141   * @param String $directory: the directory
142   * @return String: directory set
143   */
144  public function setDirectory($directory)
145  {
146    if(substr($directory,-1)!='/') $directory.='/';
147
148    // check if directory is valid
149    if(file_exists($directory) and !$this->isOpen())
150    {
151      $this->fileDir=$directory;
152    }
153    return($this->fileDir);
154  }
155
156  /**
157   * set the file name
158   *
159   * @param String $fileName: file name
160   * @return String: file name
161   */
162  public function setFileName($fileName)
163  {
164    if($this->fileName!=$fileName)
165    {
166      if($this->close()) $this->fileName=$fileName;
167    }
168    return($this->fileName);
169  }
170
171  /**
172   * return information, if set file exists or not
173   *
174   * @return Integer : 0x00 not exist (ASDF_EXIST_NO)
175   *                   0x01 exist, packed (ASDF_EXIST_PACKED)
176   *                   0x02 exist, unpacked ASDF_EXIST_UNPACKED
177   */
178  public function fileExist()
179  {
180    $returned=ASDF_EXIST_NO;
181    if($this->getFileName(ASDF_EXIST_UNPACKED)!='')
182      $returned=$returned | ASDF_EXIST_UNPACKED;
183
184    if($this->getFileName(ASDF_EXIST_PACKED)!='')
185      $returned=$returned | ASDF_EXIST_PACKED;
186
187    return($returned);
188  }
189
190  /**
191   * set the sqlite file name to retrieve IP country values
192   * $file must exist
193   *
194   * @param String $file
195   * @return String: file name set
196   */
197  public function setIpCountryFile($file)
198  {
199    if(file_exists($file))
200      $this->ipCountryFile=$file;
201    return($this->ipCountryFile);
202  }
203
204  /**
205   * return the sqlite file name used to retrieve IP country values
206   *
207   * @return String
208   */
209  public function getIpCountryFile()
210  {
211    return($this->ipCountryFile);
212  }
213
214
215  /**
216   * open the filename
217   * if $mode=ASDF_OPEN_WRITE and file doesn't exist, create it; if a packed file
218   * exist, try to unpack the packed file; in this case the unpacked file will be
219   * packed and removed automatically when the process will close.
220   *
221   * if $mode=ASDF_OPEN_READ, and unpacked file doesn't exist, try to unpack
222   * packed file (if exists); in this case the unpacked file will be removed
223   * automatically when the process will close.
224   *
225   * @param Integer $mode: READ or WRITE
226   * @return Boolean: true if opened, otherwise false
227   */
228  public function open($mode=ASDF_OPEN_READ)
229  {
230    $dbFile=$this->getFileName(ASDF_EXIST_UNPACKED, true);
231
232    /*
233     * encountered bug: sometime, an unpacked file stay with a zero size length
234     * in this case, assume to unpack packed file
235     */
236    if($dbFile!='' and filesize($dbFile)==0)
237    {
238      unlink($dbFile);
239      $dbFile='';
240    }
241
242    if($dbFile=='')
243    {
244      // file doesn't exist, check if a packed file exist
245      $dbFileP=$this->getFileName(ASDF_EXIST_PACKED, true);
246      if($dbFileP=='' and $mode==ASDF_OPEN_READ) return(false); //no packed file to open for READ, exit
247
248      if($dbFileP!='')
249      {
250        $this->unpack(); //unpack the file
251        $this->deleteUnpackedWhenClose=ASDF_CLOSE_DO_DELETE; // the unpacked file will be deleted when the process will close
252      }
253    }
254
255    switch($mode)
256    {
257      case ASDF_OPEN_READ:
258        $dbFile=$this->getFileName(ASDF_EXIST_UNPACKED, true);
259        if($dbFile=='') return(false); //big problem with unpacked file!?
260        $this->dbHandle=new SQLite3($dbFile, SQLITE3_OPEN_READONLY);
261        if($this->dbHandle) return(true);
262        break;
263      case ASDF_OPEN_WRITE:
264        $dbFile=$this->getFileName(ASDF_EXIST_UNPACKED);
265        //if file was unpacked, pack it before deleting
266        if($this->deleteUnpackedWhenClose==ASDF_CLOSE_DO_DELETE) $this->deleteUnpackedWhenClose=$this->deleteUnpackedWhenClose|ASDF_CLOSE_DO_PACK;
267        $this->dbHandle=new SQLite3($dbFile, SQLITE3_OPEN_READWRITE | SQLITE3_OPEN_CREATE);
268
269        if($this->dbHandle) $this->checkSchema();
270        return(true);
271        break;
272    }
273
274    return(false);
275  }
276
277  /**
278   * close the file
279   *
280   * @return Boolean : true if file is closed
281   */
282  public function close()
283  {
284    if($this->dbHandle==null) return(true);
285    $this->stopTransac();
286
287    if($this->dbHandle->close())
288    {
289      if(($this->deleteUnpackedWhenClose&ASDF_CLOSE_DO_PACK)==ASDF_CLOSE_DO_PACK)
290      {
291        $this->pack();
292      }
293
294      if(($this->deleteUnpackedWhenClose&ASDF_CLOSE_DO_DELETE)==ASDF_CLOSE_DO_DELETE)
295      {
296        $this->delete(ASDF_DELETE_UNPACKED);
297      }
298
299      $this->deleteUnpackedWhenClose=ASDF_CLOSE_DO_NOTHING;
300      $this->dbHandle=null;
301      return(true);
302    }
303    return(false);
304  }
305
306  /**
307   * pack the data file in a .gz file
308   *
309   * @return Bool : false if a problem happened
310   */
311  public function pack()
312  {
313    $files=array();
314
315    $file=$this->getFileName(ASDF_EXIST_UNPACKED, true);
316
317    if($file!='')
318      return(GPCCompress::gzip($file, $this->getFileName(ASDF_EXIST_PACKED)));
319    return(false);
320  }
321
322  /**
323   * unpack the .gz file
324   *
325   * @return Boolean : false if an error occurs
326   */
327  public function unpack()
328  {
329    if($this->fileExist() & ASDF_EXIST_PACKED==ASDF_EXIST_PACKED)
330    {
331      $returned=GPCCompress::gunzip($this->getFileName(ASDF_EXIST_PACKED), $this->getFileName(ASDF_EXIST_UNPACKED));
332      /*
333      $dir=dirName(dirName($this->getFileName(ASDF_EXIST_UNPACKED)));
334      $tH=fopen($dir.'/logs.log', 'a');
335      if($tH)
336      {
337        $dest=$this->getFileName(ASDF_EXIST_UNPACKED);
338        fwrite($tH, sprintf("%s - %30s - %10d - %s\n", date('Y-m-d H:i:s'), $dest, filesize($dest), $returned?'y':'n'));
339        fclose($tH);
340      }
341*/
342      return($returned);
343    }
344  }
345
346  /**
347   * delete the file
348   *
349   * $mode can take this option
350   *  - ASDF_DELETE_PACKED : delete packed file if exists
351   *  - ASDF_DELETE_UNPACKED : delete unpacked file if exists
352   * option can be combined with a pipe
353   *
354   * @param Integer $mode : delete mode to apply
355   * @return Integer :
356   */
357  public function delete($mode)
358  {
359    $returned=0;
360    if(($mode & ASDF_DELETE_PACKED)==ASDF_DELETE_PACKED)
361    {
362      if($this->getFileName(ASDF_EXIST_PACKED, true)!='')
363      {
364        if(unlink($this->getFileName(ASDF_EXIST_PACKED))) $returned=ASDF_DELETE_PACKED;
365      }
366    }
367
368    if(($mode & ASDF_DELETE_UNPACKED)==ASDF_DELETE_UNPACKED)
369    {
370      $ok=true;
371      if($this->getFileName(ASDF_EXIST_UNPACKED, true)!='') $ok=unlink($this->getFileName(ASDF_EXIST_UNPACKED));
372      if($ok) $returned=$returned | ASDF_DELETE_UNPACKED;
373    }
374
375    return($returned);
376  }
377
378  /**
379   * return true is the file is open
380   *
381   * @return Boolean
382   */
383  public function isOpen()
384  {
385    return($this->dbHandle!=null);
386  }
387
388  /**
389   * return the file name
390   *
391   * @return String
392   */
393  public function getName()
394  {
395    return($this->fileName);
396  }
397  /**
398   * return the directory
399   *
400   * @return String
401   */
402  public function getDirectory()
403  {
404    return($this->fileDir);
405  }
406
407  /**
408   * return the physical file name
409   *
410   * @param Integer $mode: ask for PACKED or UNPACKED file name
411   * @return String: file name if file exists, otherwise ''
412   */
413  public function getFileName($mode=ASDF_EXIST_UNPACKED, $onlyIfExist=false)
414  {
415    $fileName='';
416    switch($mode)
417    {
418      case ASDF_EXIST_PACKED:
419        $fileName=$this->fileDir.$this->fileName.$this->fileRootName.ASDF_FILE_EXT_ZIP;
420        break;
421      case ASDF_EXIST_UNPACKED:
422        $fileName=$this->fileDir.$this->fileName.$this->fileRootName.ASDF_FILE_EXT;
423        break;
424    }
425
426    if($onlyIfExist)
427    {
428      if($fileName!='' and file_exists($fileName)) return($fileName);
429      return('');
430    }
431    return($fileName);
432  }
433
434  /**
435   * begin a transaction
436   *
437   * usefull for performances when mass update are needed
438   *
439   * @return Boolean: true if the transaction is opened, otherwise false
440   */
441  public function startTransac()
442  {
443    if($this->dbHandle==null or $this->transacOpen) return(false);
444
445    if($this->dbHandle->exec("BEGIN TRANSACTION"))
446    {
447      $this->transacOpen=true;
448      return(true);
449    }
450    return(false);
451  }
452
453  /**
454   * stop an opened transaction
455   *
456   * @param Integer $mode: COMMIT (ASDF_TRANSAC_COMMIT) or ROLLBACK (ASDF_TRANSAC_ROLLBACK) the current transaction
457   * @return Boolean: true if the transaction is opened, otherwise false
458   */
459  public function stopTransac($mode=ASDF_TRANSAC_COMMIT)
460  {
461    if($this->dbHandle==null or !$this->transacOpen) return(false);
462
463    $returned=false;
464
465    switch($mode)
466    {
467      case ASDF_TRANSAC_COMMIT:
468        $returned=$this->dbHandle->exec("COMMIT TRANSACTION");
469        break;
470      case ASDF_TRANSAC_ROLLBACK:
471        $returned=$this->dbHandle->exec("ROLLBACK TRANSACTION");
472        break;
473    }
474
475    if($returned) $this->transacOpen=false;
476    return($returned);
477  }
478
479
480  /**
481   * set a value in the infos tables
482   * if key doesn't exist, insert it
483   *
484   * @param String $domain: domain to update
485   * @param String $key: key to update
486   * @param String $value: value to set
487   * @return Boolean
488   */
489  public function setInfoProperty($domain, $key, $value)
490  {
491    if($this->dbHandle==null) return(false);
492    $sql="REPLACE INTO info (domain, key, value)
493            VALUES('".$this->dbHandle->escapeString($domain)."',
494                   '".$this->dbHandle->escapeString($key)."',
495                   '".$this->dbHandle->escapeString($value)."');";
496    return($this->dbHandle->exec($sql));
497  }
498
499  /**
500   * get a value from the info tables
501   * if key doesn't exist, return null by default
502   *
503   * @param String $domain: domain to update
504   * @param String $key: key to update
505   * @param String $value: default value if not found
506   * @return Boolean
507   */
508  public function getInfoProperty($domain, $key, $value=null)
509  {
510    if($this->dbHandle==null) return($value);
511    $sql="SELECT value
512          FROM info
513          WHERE domain = '".$this->dbHandle->escapeString($domain)."'
514            AND key = '".$this->dbHandle->escapeString($key)."';";
515    $returned=$this->dbHandle->querySingle($sql);
516    if($returned==null) $returned=$value;
517    return($returned);
518  }
519
520  /**
521   * check, create & update the schema of the database
522   *
523   * automatically called when the file is opened
524   *
525   * the table 'info' is created by default
526   */
527  protected function checkSchema()
528  {
529    if($this->dbHandle)
530    {
531      $result=$this->getDBInfo(ASDF_DB_TYPE_TABLE, 'info', ASDF_DB_INFO);
532      if(count($result)==0)
533      {
534        $this->dbHandle->exec(
535            "CREATE TABLE 'info' (
536                'domain' TEXT,
537                'key' TEXT,
538                'value' TEXT
539            );"
540          );
541        $this->dbHandle->exec("CREATE UNIQUE INDEX iInfo ON info ('domain', 'key');");
542
543        $this->dbHandle->exec("
544          INSERT INTO info (domain, key, value) VALUES ('nfo', 'create', '".date('Y-m-d H:i:s')."');
545          INSERT INTO info (domain, key, value) VALUES ('nfo', 'version', '00.00.00');
546
547          INSERT INTO info (domain, key, value) VALUES ('log', 'buildStatPeriod-count', '0');
548        ");
549      }
550      return(true);
551    }
552    return(false);
553  }
554
555  /**
556   * return table infos
557   *
558   * $mode=ASDF_DB_INFO
559   *    return the table structure, one row per field
560   *        'name' => field name
561   *        'type' => field type
562   *
563   * $mode=ASDF_DB_NUM_ROWS
564   *    return the number of rows in the table
565   *
566   * @param Integer $type: ASDF_DB_TYPE_TABLE, ASDF_DB_TYPE_INDEX, ASDF_DB_TYPE_TRIGGER
567   * @param String $name
568   * @param Integer $mode : ASDF_DB_INFO, ASDF_DB_NUM_ROWS
569   * @return :
570   */
571  protected function getDBInfo($type, $name, $mode=0)
572  {
573    if($this->dbHandle==null) return(null);
574
575    switch($type)
576    {
577      case ASDF_DB_TYPE_TABLE:
578          switch($mode)
579          {
580            case ASDF_DB_INFO:
581                $returned=array();
582                $result=$this->dbHandle->query("PRAGMA table_info('$name')");
583                if($result)
584                {
585                  while($row=$result->fetchArray(SQLITE3_ASSOC))
586                  {
587                    $returned[]=array(
588                      'name' => $row['name'],
589                      'type' => $row['type']
590                    );
591                  }
592                }
593              break;
594            case ASDF_DB_NUM_ROWS:
595                $returned=$this->dbHandle->querySingle("SELECT COUNT(*) FROM $name");
596              break;
597            case ASDF_DB_LIST:
598                $returned=array();
599                $result=$this->dbHandle->query("SELECT name FROM sqlite_master WHERE type='table';");
600                if($result)
601                {
602                  while($row=$result->fetchArray(SQLITE3_ASSOC))
603                  {
604                    $returned[]=$row['name'];
605                  }
606                }
607              break;
608          }
609        break;
610      case ASDF_DB_TYPE_INDEX:
611          $returned=$this->dbHandle->querySingle("SELECT COUNT(*) FROM sqlite_master WHERE type = 'index' AND name='$name'");
612        break;
613      case ASDF_DB_TYPE_TRIGGER:
614          $returned=$this->dbHandle->querySingle("SELECT COUNT(*) FROM sqlite_master WHERE type = 'trigger' AND name='$name'");
615        break;
616      case ASDF_DB_TYPE_LOG:
617          $returned=array();
618          if(count($this->getDBInfo(ASDF_DB_TYPE_TABLE, 'info', ASDF_DB_INFO))==0) return($returned);
619          $result=$this->dbHandle->query("SELECT key, value FROM info WHERE domain='log';");
620          if($result)
621          {
622            while($row=$result->fetchArray(SQLITE3_ASSOC))
623            {
624              $returned[]=$row;
625            }
626          }
627        break;
628      case ASDF_DB_TYPE_NFO:
629          $returned=array();
630          if(count($this->getDBInfo(ASDF_DB_TYPE_TABLE, 'info', ASDF_DB_INFO))==0) return($returned);
631          $result=$this->dbHandle->query("SELECT key, value FROM info WHERE domain='nfo';");
632          if($result)
633          {
634            while($row=$result->fetchArray(SQLITE3_ASSOC))
635            {
636              $returned[]=$row;
637            }
638          }
639        break;
640    }
641
642    return($returned);
643  }
644
645  /**
646   * return pragma info
647   *
648   * @param String $pragma: a sqlite pragma command
649   * @return: if single data is returned, return the data otherwise return an array
650   */
651  protected function getPragma($pragma)
652  {
653    $returned=array();
654
655    if($this->dbHandle==null) return($returned);
656
657    $sql="PRAGMA ".$pragma;
658    $result=$this->dbHandle->query($sql);
659    if($result)
660    {
661      while($row=$result->fetchArray(SQLITE3_ASSOC))
662      {
663        $returned[]=$row;
664      }
665      if(count($returned)==1) $returned=$returned[0][$pragma];
666    }
667    return($returned);
668  }
669
670
671
672  /**
673   * build a where clause from a filter array
674   * used by functions:
675   *  . getLogs()
676   *  . getStatIP()
677   *  . getStatCat()
678   *  . getStatImages()
679   *
680   * return a string:
681   *  . empty '' string if there's no item to filter
682   *  . a ready to use ' WHERE ' clause string
683   *
684   * @param Array $filter: a valid filter
685   * @param Array &$IPList: an array, used to return a ':IPn' list for requests
686   *                        filtering IP adress
687   * @return String
688   */
689  protected function buildWhereClause($filter, &$IPList)
690  {
691    $where=array();
692    $IPList=array();
693    $num=0;
694
695    if(!is_array($filter)) return('');
696
697    foreach($filter as $field => $param)
698    {
699      if(is_array($param))
700      {
701        switch($param['operator'])
702        {
703          case '=':
704          case '>':
705          case '>=':
706          case '<':
707          case '<=':
708          case '!=':
709            if($field=='IPadress')
710            {
711              $IPList[$num]=$param['value'];
712              $param['value']=':IP'.$num;
713              $num++;
714            }
715            $where[]=' '.$field.' '.$param['operator']." ".$param['value']." ";
716            break;
717          case 'in':
718            if($field=='IPadress')
719            {
720              foreach($param['value'] as $key=>$ipAdress)
721              {
722                $IPList[$num]=$ipAdress;
723                $param[$key]['value']=':IP'.$num;
724                $num++;
725              }
726            }
727            $where[]=' '.$field." IN (".implode(',', $param['value']).") ";
728            break;
729          case 'between':
730            if($field=='IPadress')
731            {
732              $IPList[$num]=$param['minValue'];
733              $param['minValue']=':IP'.$num;
734              $num++;
735              $IPList[$num]=$param['maxValue'];
736              $param['maxValue']=':IP'.$num;
737              $num++;
738            }
739            $where[]=' '.$field." BETWEEN ".$param['minValue']." AND ".$param['maxValue']." ";
740            break;
741        }
742      }
743    }
744
745    if(count($where)>0)
746    {
747      $where=" WHERE ".implode(' AND ', $where)." ";
748    }
749    else
750    {
751      $where='';
752    }
753
754    return($where);
755  }
756
757
758
759  /**
760   * build an ORDER BY clause
761   * used by functions:
762   *  . getLogs()
763   *  . getStatIP()
764   *  . getStatCat()
765   *  . getStatImages()
766   *
767   * return a string:
768   *  . empty '' string if there's no limits
769   *  . a ready to use ' ORDER BY ' clause string
770   *
771   * @param Array $filter: a valid order by list
772   * @return String
773   */
774  protected function buildOrderByClause($orderBy)
775  {
776    $order=array();
777    foreach($orderBy as $sort)
778    {
779      $order[]=' '.$sort['id'].' '.($sort['direction']=='A'?'ASC':'DESC');
780    }
781
782    if(count($order)>0)
783    {
784      $orderBy=" ORDER BY ".implode(',', $order);
785    }
786    else
787    {
788      $orderBy='';
789    }
790
791    return($orderBy);
792  }
793
794
795
796  /**
797   * build a LIMIT clause
798   * used by functions:
799   *  . getLogs()
800   *  . getStatIP()
801   *  . getStatCat()
802   *  . getStatImages()
803   *
804   * return a string:
805   *  . empty '' string if there's no limits
806   *  . a ready to use ' LIMIT x,y ' clause string
807   *
808   * @param Integer $page: page number
809   * @param Integer $nbItemsPage: number of items per page
810   * @return String
811   */
812  protected function buildLimitClause($page, $nbItemsPage)
813  {
814    if($page<=0 or $nbItemsPage<=0)
815    {
816      $limit='';
817    }
818    else
819    {
820      $limit=' LIMIT '.(($page-1)*$nbItemsPage).', '.$nbItemsPage;
821    }
822
823    return($limit);
824  }
825
826
827
828  /**
829   * check if value is a valid operator array
830   * if not, return a null value otherwise return the operator
831   *
832   * validity of value are checked according to the format; valid format are:
833   *  - 'date'    => 'YYYY-MM-DD (HH:II(:SS))'
834   *  - 'IP'      => 'xxx.xxx.xxx.xxx' for IPv4, 'xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx' for IPv6
835   *  - 'string'  => a string
836   *  - 'integer' => any positive integer value
837   *
838   * @param Array $value
839   * @param String $format
840   * @return Array:
841   */
842  protected function getOperator($value, $format)
843  {
844    $returned=null;
845    if($value==null) return(null);
846    if(is_array($value))
847    {
848      if(isset($value['operator']))
849      {
850        switch($value['operator'])
851        {
852          case '=':
853          case '>':
854          case '>=':
855          case '<':
856          case '<=':
857          case '!=':
858            if(isset($value['value']))
859            {
860              switch($format)
861              {
862                case 'date':
863                  $value['value']=$this->checkValueDate($value['value']);
864                  if($value['value']==null) return(null);
865                  $value['value']=$value['value'];
866                  break;
867                case 'IP':
868                  $value['value']=$this->checkValueIP($value['value']);
869                  if($value['value']==null) return(null);
870                  break;
871                case 'string':
872                  if(!is_string($value['value']) or $value['value']=='') return(null);
873                  $value['value']="'".$value['value']."'";
874                  break;
875                case 'integer':
876                  if(!is_int($value['value']) or $value['value']<0) return(null);
877                  break;
878              }
879              $returned=$value;
880            }
881            break;
882          case 'in':
883            if(isset($value['value']) and is_array($value['value']))
884            {
885              $returned=array();
886              foreach($value['value'] as $val)
887              {
888                switch($format)
889                {
890                  case 'date':
891                    $val=$this->checkValueDate($val);
892                    if($val!=null) $returned[]=$val;
893                    break;
894                  case 'IP':
895                    $val=$this->checkValueIP($val);
896                    if($val!=null) $returned[]=$val;
897                    break;
898                  case 'string':
899                    if(is_string($val) and $val!='') $returned[]="'".$val."'";
900                    break;
901                  case 'integer':
902                    if(is_int($val*1) and $val>=0) $returned[]=$val;
903                    break;
904                }
905              }
906              if(count($returned)==0) return(null);
907              $value['value']=$returned;
908              $returned=$value;
909            }
910            break;
911          case 'between':
912            if(isset($value['minValue']) and  isset($value['maxValue']))
913            {
914              switch($format)
915              {
916                case 'date':
917                  $value['minValue']=$this->checkValueDate($value['minValue']);
918                  if($value['minValue']==null) return(null);
919                  $value['maxValue']=$this->checkValueDate($value['maxValue']);
920                  if($value['maxValue']==null) return(null);
921                  break;
922                case 'IP':
923                  $value['minValue']=$this->checkValueIP($value['minValue']);
924                  if($value['minValue']==null) return(null);
925                  $value['maxValue']=$this->checkValueIP($value['maxValue']);
926                  if($value['maxValue']==null) return(null);
927                  break;
928                case 'string':
929                  if(!is_string($value['minValue']) or $value['minValue']=='' or
930                     !is_string($value['maxValue']) or $value['maxValue']=='') return(null);
931
932                  $value['minValue']="'".$value['minValue']."'";
933                  $value['maxValue']="'".$value['maxValue']."'";
934                  break;
935                case 'integer':
936                  if(!is_int($value['minValue']) or $value['minValue']<0 or
937                     !is_int($value['maxValue']) or $value['maxValue']<0) return(null);
938                  break;
939              }
940              if($value['minValue']>$value['maxValue']) return(null);
941              $returned=$value;
942            }
943            break;
944        }
945      }
946    }
947    return($returned);
948  }
949
950  /**
951   * check if date is Ok
952   * return the date completed (YYYY-MM-DD => YYYY-MM-DD 00:00:00) or null if not valid
953   *
954   * @param String $value
955   * @return String
956   */
957  protected function checkValueDate($value)
958  {
959    $returned=null;
960    $result=array();
961    if(preg_match('/^(\d{4}-\d{2}-\d{2})(?:(\s{1}\d{2}:\d{2})(:\d{2})?)?$/', $value, $result)>0)
962    {
963      $returned=$result[1];
964      if(isset($result[2]))
965      {
966        $returned.=$result[2];
967        if(isset($result[3]))
968        {
969          $returned.=$result[3];
970        }
971        else $returned.=':00';
972      }
973      else $returned.=' 00:00:00';
974    }
975    return(strtotime($returned));
976  }
977
978  /**
979   * check if IP is Ok (IPv4 or IPv6)
980   * return the IP or null
981   *
982   * @param String $value
983   * @return String
984   */
985  protected function checkValueIP($value)
986  {
987    $returned=self::IPBinaryEncode($value);
988    if($returned=="\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00") return(null);
989    return($returned);
990  }
991
992
993
994
995
996
997
998  /**
999   * return an IP adress with format 'xxx.xxx.xxx.xxx' as a binary encoded string
1000   *
1001   * @param String $IP: text IP string
1002   * @return String: a binary string
1003   */
1004  static public function IPBinaryEncode($IP)
1005  {
1006    $value=trim($IP);
1007    if(preg_match('/\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/i',$value)>0)
1008    {
1009      //IPv4
1010      $tmp=explode('.',$value);
1011      return("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".chr($tmp[0]+0).chr($tmp[1]+0).chr($tmp[2]+0).chr($tmp[3]+0));
1012    }
1013    elseif(preg_match('/[a-f0-9]{0,4}:[a-f0-9]{0,4}:[a-f0-9]{0,4}:[a-f0-9]{0,4}:[a-f0-9]{0,4}:[a-f0-9]{0,4}:[a-f0-9]{0,4}:[a-f0-9]{0,4}/i',$value))
1014    {
1015      //IPv6
1016    }
1017    else
1018    {
1019      return("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00");
1020    }
1021  }
1022
1023  /**
1024   * return an IP adress with format 'xxx.xxx.xxx.xxx' from a binary encoded string
1025   *
1026   * @param String $IP: binary encoded string
1027   * @return String: a text IP string
1028   */
1029  static public function IPBinaryDecode($IP)
1030  {
1031    $returned='';
1032    if(strlen($IP)==16)
1033    {
1034      if(substr($IP,0,12)=="\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00")
1035      {
1036        //IPv4
1037        $returned=sprintf('%d.%d.%d.%d', ord(substr($IP,12,1)), ord(substr($IP,13,1)), ord(substr($IP,14,1)), ord(substr($IP,15,1)));
1038      }
1039      else
1040      {
1041        //IPv6
1042      }
1043    }
1044    else if(strlen($IP)==4)
1045    {
1046      $returned=sprintf('%d.%d.%d.%d', ord(substr($IP,0,1)), ord(substr($IP,1,1)), ord(substr($IP,2,1)), ord(substr($IP,3,1)));
1047    }
1048    else
1049    {
1050    }
1051    return($returned);
1052  }
1053
1054
1055  /**
1056    * Convert the given data into an unsigned Short integer (16bit)
1057    *
1058    * @param String $data       : representing the unsigned Short
1059    * @param String $endianType : the byte order
1060    * @return UShort
1061    */
1062  static public function toUShort($data)
1063  {
1064    if(strlen($data)>=2)
1065      return(ord($data{0})*256 + ord($data{1}));
1066    return(0);
1067  }
1068
1069  /**
1070    * Convert the given data into an unsigned Long integer (32bit)
1071    *
1072    * @param String $data       : representing the unsigned Long
1073    * @param String $endianType : the byte order
1074    * @return ULong
1075    */
1076  static public function toULong($data)
1077  {
1078    if(strlen($data)>=4)
1079        return(ord($data{0})*16777216 +
1080                ord($data{1})*65536 +
1081                ord($data{2})*256 +
1082                ord($data{3}));
1083    return(0);
1084  }
1085
1086
1087}
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097?>
Note: See TracBrowser for help on using the repository browser.