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
|