468 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			468 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
| <?php
 | |
| namespace ShortPixel\Model;
 | |
| 
 | |
| if ( ! defined( 'ABSPATH' ) ) {
 | |
|  exit; // Exit if accessed directly.
 | |
| }
 | |
| 
 | |
| use ShortPixel\ShortPixelLogger\ShortPixelLogger as Log;
 | |
| 
 | |
| use ShortPixel\Controller\OtherMediaController as OtherMediaController;
 | |
| use ShortPixel\Model\Image\ImageModel as ImageModel;
 | |
| use ShortPixel\Model\Image\MediaLibraryModel as MediaLibraryModel;
 | |
| 
 | |
| 
 | |
| use ShortPixel\Helper\UtilHelper as UtilHelper;
 | |
| use ShortPixel\Helper\InstallHelper as InstallHelper;
 | |
| 
 | |
| 
 | |
| class StatsModel
 | |
| {
 | |
| 
 | |
|   // Below are counted and saved in settings
 | |
|   protected $totalOptimized; // combined filesize of optimized images
 | |
|   protected $totalOriginal;  // combined filesize of original images
 | |
| 
 | |
|   // There are gotten via SQL and saved in stats
 | |
|   //protected $totalImages;
 | |
|   //protected $totalThumbnails
 | |
| 
 | |
|   protected $lastUpdate;
 | |
|   protected $path = array();
 | |
| 
 | |
|   protected $currentStat;  // used for chaining it.
 | |
| 
 | |
|   protected $refreshStatTime;
 | |
| 
 | |
| 
 | |
|   // Commented out stats were dropped.
 | |
|   // Note: the difference in items / images including thumbs and the counts don't . This is due to technical difference in acquiring the data.
 | |
|     protected $defaults = array(
 | |
|       'media' => array('items' => -1, // total optimized media items found
 | |
|                        'images' => -1, // total optimized images (+thumbs) found
 | |
|                        'thumbs' => -1, // Optimized thumbs - SQL does thumbs, but queue doesn't. (imprecise query)
 | |
|                        'itemsTotal' => -1, // Total items in media  ( sql )
 | |
|                        'thumbsTotal' => -1, // Total thumbs in media ( sql ) - imprecise query
 | |
| 											 'isLimited' => false,
 | |
|                   /*     'lossy' => 0, // processed x compression
 | |
|                        'lossy_thumbs' => 0, // main / thumbs
 | |
|                        'lossless' => 0, // main /thumbs
 | |
|                        'lossless_thumbs' => 0,
 | |
|                        'glossy' => 0,
 | |
|                        'glossy_thumbs' => 0, */
 | |
|       ),
 | |
|       'custom' => array('items' => -1, // total optimized custom items
 | |
|                         'images' => -1, // total optimized custom images
 | |
|                         'itemsTotal' => -1,
 | |
| 
 | |
|                       /*  'lossy' => 0, // process x compression
 | |
|                         'lossless' => 0,
 | |
|                         'glossy' => 0, */
 | |
|       ),
 | |
|       'period' => array('months' =>  // amount of images compressed in x month
 | |
|                     array('1' => -1,  /// count x months ago what was done.
 | |
|                         '2' => -1,
 | |
|                         '3' => -1,
 | |
|                         '4' => -1,
 | |
|                     ),
 | |
|       ),
 | |
|       'total' => array('items' => -1,
 | |
|                        'images' => -1,
 | |
|                        'thumbs' => -1,
 | |
|                        'itemsTotal' => -1,
 | |
|                        'thumbsTotal' => -1,
 | |
|                      ),
 | |
| 
 | |
|     /*  'total' => array('items' => 0,  // total items found
 | |
|                        'images' => 0, // total images found
 | |
|       ), */
 | |
|   );
 | |
| 
 | |
|   protected $stats;  // loaded as defaults, or from dbase.
 | |
| 
 | |
|   public function __construct()
 | |
|   {
 | |
|       $this->refreshStatTime = apply_filters('shortpixel/statistics/refresh', WEEK_IN_SECONDS);
 | |
|       $this->load();
 | |
|   }
 | |
| 
 | |
|   public function load()
 | |
|   {
 | |
|     $settings = \wpSPIO()->settings();
 | |
| 
 | |
|     $this->totalOptimized = $settings->totalOptimized;
 | |
|     $this->totalOriginal = $settings->totalOriginal;
 | |
| 
 | |
|     $stats = $settings->currentStats;
 | |
| 
 | |
|     // Legacy. Stats from < 5.0 are loaded somehow. Don't load them.
 | |
|     if (isset($stats['APIKeyValid']))
 | |
|       $stats = $this->defaults;
 | |
| 
 | |
|     $this->lastUpdate = (isset($stats['time'])) ? $stats['time'] : 0;
 | |
| 
 | |
|     if ( ($this->lastUpdate + $this->refreshStatTime) >= time())
 | |
|     {
 | |
|        $this->stats = $stats;
 | |
|     }
 | |
|     else
 | |
|       $this->stats = $this->defaults;
 | |
| 
 | |
|   }
 | |
| 
 | |
|   public function save()
 | |
|   {
 | |
|      $settings = \wpSPIO()->settings();
 | |
|      $stats = $this->stats;
 | |
|      $stats['time'] = time();
 | |
| 
 | |
|      $settings->currentStats = $stats;
 | |
|   }
 | |
| 
 | |
|   public function reset()
 | |
|   {
 | |
|       $this->stats = $this->defaults;
 | |
| 			\wpSPIO()->settings()->deleteOption('currentStats');
 | |
| 
 | |
|   //    $this->save();
 | |
|   }
 | |
| 
 | |
|   // @todo This is not functional
 | |
|   public function add($stat)
 | |
|   {
 | |
|      if (property_exists($stat, 'images'))
 | |
|          $this->stats[$stat->type][$images] += $stats->images;
 | |
|      if (property_exists($stat, 'items'))
 | |
|         $this->stats[$stat->type][$items] += $stats->items;
 | |
| 
 | |
| 
 | |
|   }
 | |
| 
 | |
|   public function get($name)
 | |
|   {
 | |
|       if (property_exists($this, $name))
 | |
|          return $this->$name;
 | |
|       else
 | |
|         return null;
 | |
|   }
 | |
| 
 | |
|   public function getStat($type)
 | |
|   {
 | |
|       $this->currentStat = null;
 | |
| 
 | |
|       if (isset($this->stats[$type]))
 | |
|       {
 | |
|          $this->currentStat = $this->stats[$type];
 | |
|          $this->path = [$type];
 | |
|       }
 | |
| 
 | |
|       return $this;
 | |
|   }
 | |
| 
 | |
|   public function grab($data)
 | |
|   {
 | |
| 
 | |
|      if (is_null($this->currentStat))
 | |
|           return null;
 | |
| 
 | |
|        if (array_key_exists($data, $this->currentStat))
 | |
|        {
 | |
|           $this->currentStat = $this->currentStat[$data];
 | |
|           $this->path[] = $data;
 | |
|        }
 | |
| 
 | |
| 
 | |
|        if (! is_array($this->currentStat))
 | |
|        {
 | |
|          if ($this->currentStat === -1)
 | |
|          {
 | |
|             $this->currentStat = $this->fetchStatdata();  // if -1 stat might not be loaded, load.
 | |
|          }
 | |
| 
 | |
|         return $this->currentStat;
 | |
|        }
 | |
|        else
 | |
| 			 {
 | |
|         return $this;
 | |
| 			 }
 | |
|   }
 | |
| 
 | |
|   private function fetchStatData()
 | |
|   {
 | |
|       $path = $this->path;
 | |
|       $data = -1;
 | |
| 
 | |
|       if ($path[0] == 'period' && $path[1] == 'months' && isset($path[2]))
 | |
|       {
 | |
|           $month = $path[2];
 | |
| 
 | |
|           $data = $this->countMonthlyOptimized(intval($month));
 | |
| 
 | |
|           if ($data >= 0)
 | |
|           {
 | |
|             $this->stats['period']['months'][$month] = $data;
 | |
|             $this->save();
 | |
|           }
 | |
| 
 | |
|       }
 | |
|       if ($path[0] == 'media')
 | |
|       {
 | |
|           switch($path[1])
 | |
|           {
 | |
|             case 'items':
 | |
|               $data = $this->countMediaItems(['optimizedOnly' => true]);
 | |
|             break;
 | |
|             case 'thumbs': // unrealiable if certain thumbs are not optimized, but the main image is.
 | |
|               $data = $this->countMediaThumbnails(['optimizedOnly' => true]);
 | |
|             break;
 | |
|             case 'images':
 | |
|               $data = $this->getStat('media')->grab('items') + $this->getStat('media')->grab('thumbs');
 | |
|             break;
 | |
|             case 'itemsTotal':
 | |
|               $data = $this->countMediaItems();
 | |
|             break;
 | |
|             case 'thumbsTotal':
 | |
|                $data = $this->countMediaThumbnails();
 | |
|             break;
 | |
| 						case 'isLimited':
 | |
| 								$data = $this->stats['media']['isLimited'];
 | |
| 						break;
 | |
|           }
 | |
| 
 | |
|           if ($data >= 0)
 | |
|           {
 | |
| 						 if (is_numeric($data))
 | |
| 						 {
 | |
| 							  $data = max($data, 0);
 | |
| 						 }
 | |
|              $this->stats['media'][$path[1]] = $data; // never allow any data below zero.
 | |
|              $this->save();
 | |
|           }
 | |
|       }
 | |
| 
 | |
| 
 | |
|       if ($path[0] == 'custom')
 | |
|       {
 | |
|           switch($path[1])
 | |
|           {
 | |
|              case 'items':
 | |
|                 $data = $this->customItems(['optimizedOnly' => true]);
 | |
|              break;
 | |
|              case 'itemsTotal':
 | |
|                 $data = $this->customItems();
 | |
|              break;
 | |
|           }
 | |
| 
 | |
|           if ($data >= 0)
 | |
|           {
 | |
|              $this->stats['custom'][$path[1]] = $data;
 | |
|              $this->save();
 | |
|           }
 | |
|       }
 | |
| 
 | |
|       if ($path[0] == 'total')
 | |
|       {
 | |
|          switch($path[1])
 | |
|          {
 | |
| 
 | |
|             case 'items':
 | |
|               $media = $this->getStat('media')->grab('items');
 | |
|               $custom = $this->getStat('custom')->grab('items');
 | |
|               $data = $media + $custom;
 | |
|             break;
 | |
|             case 'images':
 | |
|               $media = $this->getStat('media')->grab('images');
 | |
|               $custom = $this->getStat('custom')->grab('items'); // items == images
 | |
|               $data = $media + $custom;
 | |
|             break;
 | |
|             case 'thumbs':
 | |
|                $data = $this->getStat('media')->grab('thumbs');
 | |
|             break;
 | |
|             case 'itemsTotal':
 | |
|                 $media = $this->getStat('media')->grab('itemsTotal');
 | |
|                 $custom = $this->getStat('custom')->grab('itemsTotal');
 | |
|                 $data = $media + $custom;
 | |
|             break;
 | |
|             case 'thumbsTotal':
 | |
|                 $data = $this->getStat('media')->grab('thumbsTotal');
 | |
|             break;
 | |
| 
 | |
|          }
 | |
|          if ($data >= 0)
 | |
|          {
 | |
|             $this->stats['total'][$path[1]] = $data;
 | |
|             $this->save();
 | |
|          }
 | |
|       }
 | |
| 
 | |
|       return $data;
 | |
| 
 | |
|   }
 | |
| 
 | |
| 
 | |
|   // suboptimal over full stats implementation, but faster.
 | |
|   private function countMediaThumbnails($args = array())
 | |
|   {
 | |
|      global $wpdb;
 | |
| 
 | |
|      $defaults = array(
 | |
|        'optimizedOnly' => false,
 | |
| 			 'limit' => 50000,
 | |
|      );
 | |
| 
 | |
|      $args = wp_parse_args($args,$defaults);
 | |
| 		 $prepare = array();
 | |
| 
 | |
|      if ($args['optimizedOnly'] == true)
 | |
|      {
 | |
|        $sql =  ' SELECT count(id) as thumbcount FROM ' . UtilHelper::getPostMetaTable() . ' WHERE status = %d AND (image_type = %d or image_type = %d)';
 | |
| 			 $prepare = array(ImageModel::FILE_STATUS_SUCCESS, MediaLibraryModel::IMAGE_TYPE_THUMB, MediaLibraryModel::IMAGE_TYPE_ORIGINAL);
 | |
|      }
 | |
| 		 else {
 | |
| 			 // This query will return 2 positions after the thumbnail array declaration.  Value can be up to two positions ( 0-100 thumbnails) . If positions is 1-10 intval will filter out the string part.
 | |
| 	     $sql = "SELECT  meta_id, post_id, substr(meta_value, instr(meta_value,'sizes')+9,2) as thumbcount, LOCATE('original_image', meta_value) as originalImage FROM " . $wpdb->postmeta . " WHERE meta_key = '_wp_attachment_metadata' ";
 | |
| 
 | |
| 	     $sql .= " AND post_id NOT IN ( SELECT post_id FROM " . $wpdb->postmeta . " where meta_key = '_shortpixel_prevent_optimize' )";  // exclude 'crashed items'
 | |
| 
 | |
| 			 $sql .= " limit 0," . $args['limit'];
 | |
| 		 }
 | |
| 
 | |
| 
 | |
| 		 if (count($prepare) > 0)
 | |
| 		 {
 | |
| 			  $sql = $wpdb->prepare($sql, $prepare);
 | |
| 		 }
 | |
| 
 | |
|      $results = $wpdb->get_results($sql);
 | |
| 
 | |
| 		 //og::addDebug('Limit and count results' . $args['limit'] . ' ' . count($results));
 | |
| 		 if ($args['limit'] <= count($results))
 | |
| 		 {
 | |
| 			 	$this->stats['media']['isLimited']= true;
 | |
| 		 }
 | |
| 
 | |
|      $thumbCount = 0;
 | |
| 
 | |
|      foreach($results as $row)
 | |
|      {
 | |
|         $count = intval($row->thumbcount);
 | |
|         if ($count > 0)
 | |
|            $thumbCount += $count;
 | |
|         if (property_exists($row, 'originalImage') && $row->originalImage > 0) // add to count, return value is string pos
 | |
|            $thumbCount++;
 | |
|      }
 | |
| 
 | |
|      return intval($thumbCount);
 | |
|   }
 | |
| 
 | |
|   private function countMediaItems($args = array())
 | |
|   {
 | |
|       global $wpdb;
 | |
| 
 | |
|       $defaults = array(
 | |
|         'optimizedOnly' => false,
 | |
|       );
 | |
| 
 | |
|       $args = wp_parse_args($args,$defaults);
 | |
| 			$prepare = array();
 | |
| 
 | |
|       if ($args['optimizedOnly'] == true)
 | |
|       {
 | |
|         //$sql .= ' AND post_id IN ( SELECT post_id FROM ' . $wpdb->postmeta . ' WHERE meta_key = "_shortpixel_optimized")';
 | |
| 				$sql = ' SELECT count(id) as count FROM ' . UtilHelper::getPostMetaTable() . ' WHERE status = %d AND parent = %d';
 | |
| 				$prepare = array(ImageModel::FILE_STATUS_SUCCESS, MediaLibraryModel::IMAGE_TYPE_MAIN);
 | |
|       }
 | |
| 			else {
 | |
| 				$sql = 'SELECT count(meta_id) FROM ' . $wpdb->postmeta . ' WHERE meta_key = "_wp_attached_file"';
 | |
|      		$sql .= " AND post_id NOT IN ( SELECT post_id FROM " . $wpdb->postmeta . " where meta_key = '_shortpixel_prevent_optimize' )";  // exclude 'crashed items'
 | |
| 			}
 | |
| 
 | |
| 			if (count($prepare) > 0)
 | |
| 				$sql = $wpdb->prepare($sql, $prepare);
 | |
| 
 | |
|       $count = $wpdb->get_var($sql);
 | |
| 
 | |
| 
 | |
| 			if (is_null($count) && strpos($wpdb->last_error, 'exist') !== false)
 | |
| 			{
 | |
| 				 InstallHelper::checkTables();
 | |
| 				 return 0;
 | |
| 			}
 | |
| 
 | |
|       return intval($count);
 | |
|   }
 | |
| 
 | |
|   private function countMonthlyOptimized($monthsAgo = 1)
 | |
|   {
 | |
|      global $wpdb;
 | |
|      //$monthsAgo = 0 - $monthsAgo; // minus it for the sub.
 | |
|      /*$sql = "select meta_id from wp_postmeta where meta_key = '_shortpixel_meta' HAVING substr(meta_value, instr(meta_value, 'tsOptimized')+15,10) as stamp >= %d and stamp <= %d"; */
 | |
| 
 | |
| 		 $date = new \DateTime();
 | |
|      $date->sub( new \DateInterval('P' . $monthsAgo . 'M'));
 | |
| 
 | |
|      $dateUntil = new \DateTime();
 | |
|      $dateUntil->sub( new \DateInterval('P' . ($monthsAgo-1). 'M'));
 | |
| 
 | |
|      $sql = 'SELECT count(id) FROM '  . $wpdb->prefix . 'shortpixel_postmeta WHERE tsOptimized >= %s and tsOptimized <= %s';
 | |
|      $sql = $wpdb->prepare($sql, $date->format('Y-m-d H:i:s'), $dateUntil->format('Y-m-d H:i:s') );
 | |
|      $count_media = $wpdb->get_var($sql);
 | |
| 
 | |
| 		 // Custom
 | |
| 		 $sql = 'SELECT count(id) FROM '  . $wpdb->prefix . 'shortpixel_meta WHERE ts_optimized >= %s and ts_optimized <= %s';
 | |
| 		 $sql = $wpdb->prepare($sql, $date->format('Y-m-d H:i:s'), $dateUntil->format('Y-m-d H:i:s') );
 | |
| 		 $count_custom = $wpdb->get_var($sql);
 | |
| 
 | |
| 		 $count = 0;
 | |
| 		 if (! is_null($count_media) && is_numeric($count_media))
 | |
| 		 	$count += $count_media;
 | |
| 
 | |
| 			if (! is_null($count_custom) && is_numeric($count_custom))
 | |
|  		 	$count += $count_custom;
 | |
| 
 | |
| 
 | |
|      return $count;
 | |
|   }
 | |
| 
 | |
|   private function customItems($args = array())
 | |
|   {
 | |
|        global $wpdb;
 | |
| 
 | |
|        $defaults = array(
 | |
|          'optimizedOnly' => false,
 | |
|        );
 | |
| 
 | |
|        $args = wp_parse_args($args,$defaults);
 | |
| 
 | |
|        $otherMediaController = OtherMediaController::getInstance();
 | |
|        if (! $otherMediaController->hasCustomImages() )
 | |
|        {
 | |
|           return 0;
 | |
|        }
 | |
| 
 | |
| 			 $activeDirectories = $otherMediaController->getActiveDirectoryIDS();
 | |
|       // $foldersids = implode(',', $activeDirectories );
 | |
| 
 | |
| 			 if (count($activeDirectories) == 0)
 | |
| 			 	  return 0; // no active folders
 | |
| 
 | |
| 					$in_str_arr = array_fill( 0, count( $activeDirectories ), '%s' );
 | |
|  				 $in_str = join( ',', $in_str_arr );
 | |
| 
 | |
|        $sql = 'SELECT COUNT(id) as count FROM ' . $wpdb->prefix . 'shortpixel_meta WHERE folder_id in (' . $in_str . ')';
 | |
| 			 $sql = $wpdb->prepare($sql, $activeDirectories);
 | |
| 
 | |
|        if ($args['optimizedOnly'] == true)
 | |
|        {
 | |
|          $sql .= ' AND status = %d';
 | |
|          $sql = $wpdb->prepare($sql, ImageModel::FILE_STATUS_SUCCESS);
 | |
|        }
 | |
| 
 | |
|         $count = $wpdb->get_var($sql);
 | |
|         return $count;
 | |
| 
 | |
|   }
 | |
| 
 | |
| 
 | |
| } // class
 |