File "Queue.php"

Full path: /home/kosmetik/public_html/wp-content/plugins/shortpixel-image-optimiser/class/Queue.php
File size: 15.59 B
MIME-type: text/x-php
Charset: utf-8

Download   Open   Edit   Advanced Editor   Back

<?php

use ShortPixel\ShortPixelLogger\ShortPixelLogger as Log;
class ShortPixelQueue
{
    protected $ctrl;
    protected $settings;
    const BULK_TYPE_OPTIMIZE = 0;
    const BULK_TYPE_RESTORE = 1;
    const BULK_TYPE_CLEANUP = 2;
    const BULK_TYPE_CLEANUP_PENDING = 3;
    const BULK_NEVER = 0;
    const BULK_RUNNING = 1;
    const BULK_PAUSED = 2;
    const BULK_FINISHED = 3;
    public function __construct($controller, $settings)
    {
        $this->ctrl = $controller;
        $this->settings = $settings;
    }
    public function ShortPixelQueue($controller)
    {
        $this->__construct($controller);
    }
    public static function get()
    {
        $fp = self::openQ(LOCK_SH);
        if (!$fp) {
            return array();
        }
        $itemsRaw = fgets($fp);
        $items = strlen($itemsRaw) ? self::parseQ($itemsRaw) : array();
        self::closeQ($fp);
        return $items;
    }
    public static function set($items)
    {
        $fp = self::openQ();
        if (!$fp) {
            return false;
        }
        fseek($fp, 0);
        ftruncate($fp, 0);
        fwrite($fp, implode(',', $items));
        fflush($fp);
        self::closeQ($fp);
        return true;
    }
    public function apply($callable, $extra = false)
    {
        $fp = self::openQ();
        if (!$fp) {
            return false;
        }
        $itemsRaw = fgets($fp);
        $items = strlen($itemsRaw) ? self::parseQ($itemsRaw) : array();
        if ($extra) {
            $items = call_user_func($callable, $items, $extra);
        } else {
            $items = call_user_func($callable, $items);
        }
        fseek($fp, 0);
        ftruncate($fp, 0);
        fwrite($fp, implode(',', $items));
        fflush($fp);
        self::closeQ($fp);
        return $items;
    }
    public static function testQ()
    {
        $fp = self::openQ();
        if ($fp === false) {
            return false;
        }
        self::closeQ($fp);
        return true;
    }
    protected static function openQ($lock = LOCK_EX)
    {
        $queueName = SHORTPIXEL_UPLOADS_BASE . "/.shortpixel-q-" . get_current_blog_id();
        $fp = @fopen($queueName, "r+");
        if (!$fp) {
            $fp = @fopen($queueName, "w");
            if (!$fp) {
                return false;
            }
        }
        flock($fp, $lock);
        return $fp;
    }
    protected static function closeQ($fp)
    {
        flock($fp, LOCK_UN);
        fclose($fp);
    }
    protected static function parseQ($items)
    {
        return explode(',', preg_replace("/[^0-9,C-]/", "", $items));
    }
    public function skip($id)
    {
        if (is_array($this->settings->prioritySkip)) {
            $this->settings->prioritySkip = array_merge($this->settings->prioritySkip, array($id));
        } else {
            $this->settings->prioritySkip = array($id);
        }
    }
    public function unskip($id)
    {
        $prioSkip = $this->settings->prioritySkip;
        $this->settings->prioritySkip = is_array($prioSkip) ? array_diff($prioSkip, array($id)) : array();
    }
    public function allSkipped()
    {
        if (!is_array($this->settings->prioritySkip)) {
            return false;
        }
        count(array_diff($this->get(), $this->settings->prioritySkip));
    }
    public function skippedCount()
    {
        return is_array($this->settings->prioritySkip) ? count($this->settings->prioritySkip) : 0;
    }
    public function isSkipped($id)
    {
        return is_array($this->settings->prioritySkip) && in_array($id, $this->settings->prioritySkip);
    }
    public function isPrio($id)
    {
        $prioItems = $this->get();
        return is_array($prioItems) && in_array($id, $prioItems);
    }
    public function getSkipped()
    {
        return $this->settings->prioritySkip;
    }
    public function reverse()
    {
        $this->apply('array_reverse');
    }
    protected function pushCallback($priorityQueue, $ID)
    {
        Log::addDebug("PUSH: Push ID {$ID} into queue " . json_encode($priorityQueue));
        array_push($priorityQueue, $ID);
        $prioQ = array_unique($priorityQueue);
        return $prioQ;
    }
    public function push($ID)
    {
        $this->apply(array(&$this, 'pushCallback'), $ID);
    }
    protected function enqueueCallback($priorityQueue, $ID)
    {
        WPShortPixel::log("ENQUEUE: Enqueue ID {$ID} into queue " . json_encode($priorityQueue));
        array_unshift($priorityQueue, $ID);
        $prioQ = array_unique($priorityQueue);
        WPShortPixel::log("ENQUEUE: Updated: " . json_encode($prioQ));
        return $prioQ;
    }
    public function enqueue($ID)
    {
        $this->apply(array(&$this, 'enqueueCallback'), $ID);
    }
    public function getFirst($count = 1)
    {
        $priorityQueue = $this->get();
        $count = min(count($priorityQueue), $count);
        return array_slice($priorityQueue, count($priorityQueue) - $count, $count);
    }
    public function getFromPrioAndCheck()
    {
        $idsPrio = $this->get();
        $ids = array();
        $removeIds = array();
        for ($i = count($idsPrio) - 1, $cnt = 0; $i >= 0 && $cnt < 3; $i--) {
            if (!isset($idsPrio[$i])) {
                continue;
            }
            $id = $idsPrio[$i];
            if (!$this->isSkipped($id) && $this->ctrl->isValidMetaId($id)) {
                $ids[] = $id;
                $cnt++;
            } elseif (!$this->isSkipped($id)) {
                $removeIds[] = $id;
            }
        }
        foreach ($removeIds as $rId) {
            WPShortPixel::log("HIP: Unfound ID {$rId} Remove from Priority Queue: " . json_encode($this->get()));
            $this->remove($rId);
        }
        return $ids;
    }
    public function remove($ID)
    {
        $fp = $this->openQ();
        if (!$fp) {
            return false;
        }
        $items = fgets($fp);
        $items = self::parseQ($items);
        $items = is_array($items) ? $items : array();
        $newItems = array();
        $found = false;
        foreach ($items as $item) {
            if ($item != $ID) {
                $newItems[] = $item;
            } else {
                $found = true;
            }
        }
        if ($found) {
            fseek($fp, 0);
            ftruncate($fp, 0);
            fwrite($fp, implode(',', $newItems));
            fflush($fp);
        }
        $this->closeQ($fp);
        return $found;
    }
    public function removeFromFailed($ID)
    {
        $failed = explode(",", $this->settings->failedImages);
        $key = array_search($ID, $failed);
        if ($key !== false) {
            unset($failed[$key]);
            $failed = array_values($failed);
            $this->settings->failedImages = implode(",", $failed);
        }
    }
    public function addToFailed($ID)
    {
        $failed = $this->settings->failedImages;
        if (!in_array($ID, explode(",", $failed))) {
            $this->settings->failedImages = (strlen($failed) ? $failed . "," : "") . $ID;
        }
    }
    public function getFailed()
    {
        $failed = $this->settings->failedImages;
        if (!strlen($failed)) {
            return array();
        }
        $ret = explode(",", $failed);
        $fails = array();
        foreach ($ret as $fail) {
            if (ShortPixelMetaFacade::isCustomQueuedId($fail)) {
                $meta = $this->ctrl->getSpMetaDao()->getMeta(ShortPixelMetaFacade::stripQueuedIdType($fail));
                if ($meta) {
                    $fails[] = (object) array("id" => ShortPixelMetaFacade::stripQueuedIdType($fail), "type" => ShortPixelMetaFacade::CUSTOM_TYPE, "meta" => $meta);
                }
            } else {
                $meta = wp_get_attachment_metadata($fail);
                if (!$meta || isset($meta["ShortPixelImprovement"]) && is_numeric($meta["ShortPixelImprovement"])) {
                    $this->removeFromFailed($fail);
                } else {
                    $fails[] = (object) array("id" => $fail, "type" => ShortPixelMetaFacade::MEDIA_LIBRARY_TYPE, "meta" => $meta);
                }
            }
        }
        return $fails;
    }
    public function bulkRunning()
    {
        return $this->settings->startBulkId > $this->settings->stopBulkId;
    }
    public function bulkPaused()
    {
        return $this->settings->cancelPointer;
    }
    public function bulkRan()
    {
        return $this->settings->bulkEverRan != 0;
    }
    public function processing()
    {
        return $this->bulkRunning() || count($this->get());
    }
    public function getFlagBulkId()
    {
        return $this->settings->flagId;
    }
    public function getStartBulkId()
    {
        return $this->settings->startBulkId;
    }
    public function resetStartBulkId()
    {
        $this->setStartBulkId(ShortPixelMetaFacade::getMaxMediaId());
    }
    public function setStartBulkId($start)
    {
        $this->settings->startBulkId = $start;
    }
    public function getStopBulkId()
    {
        return $this->settings->stopBulkId;
    }
    public function resetStopBulkId()
    {
        $this->settings->stopBulkId = ShortPixelMetaFacade::getMinMediaId();
    }
    public function setBulkPreviousPercent()
    {
        $res = $this->settings->currentStats;
        $this->settings->bulkCount = $res["mainFiles"];
        switch (0 + $this->ctrl->getCompressionType()) {
            case 2:
                $this->settings->bulkAlreadyDoneCount = $res["mainProcessedFiles"] - $res["mainProcLossyFiles"] - $res["mainProcLosslessFiles"];
                break;
            case 1:
                $this->settings->bulkAlreadyDoneCount = $res["mainProcessedFiles"] - $res["mainProcGlossyFiles"] - $res["mainProcLosslessFiles"];
                break;
            default:
                $this->settings->bulkAlreadyDoneCount = $res["mainProcessedFiles"] - $res["mainProcLossyFiles"] - $res["mainProcGlossyFiles"];
                break;
        }
        if ($this->settings->processThumbnails) {
            $this->settings->bulkAlreadyDoneCount -= $res["mainUnprocessedThumbs"];
        }
        $this->settings->bulkPreviousPercent = round($this->settings->bulkAlreadyDoneCount / ($this->settings->bulkCount ? $this->settings->bulkCount : 1) * 100);
    }
    public function getBulkToProcess()
    {
        if (!is_numeric($this->settings->bulkCount)) {
            $this->settings->bulkCount = 0;
        }
        if (!is_numeric($this->settings->bulkAlreadyDoneCount)) {
            $this->settings->bulkAlreadyDoneCount = 0;
        }
        return $this->settings->bulkCount - $this->settings->bulkAlreadyDoneCount;
    }
    public function flagBulkStart()
    {
        $this->settings->flagId = $this->settings->startBulkId;
        $this->settings->bulkProcessingStatus = 'running';
    }
    public function setBulkType($type)
    {
        $this->settings->bulkType = $type;
    }
    public function getBulkType()
    {
        return $this->settings->bulkType;
    }
    public function getBulkTypeForDisplay()
    {
        $bulk = $this->settings->bulkType;
        $this->settings->bulkType = null;
        return $bulk;
    }
    public function startBulk($type = self::BULK_TYPE_OPTIMIZE)
    {
        Log::addDebug('startBulk 0');
        $this->resetStartBulkId();
        $this->resetStopBulkId();
        $this->flagBulkStart();
        $this->setBulkPreviousPercent();
        $this->resetBulkCurrentlyProcessed();
        $this->setBulkType($type);
        $this->settings->bulkEverRan = 1;
    }
    public function pauseBulk()
    {
        $cancelPointer = $this->settings->startBulkId;
        $bulkStartId = $this->getFlagBulkId();
        $this->settings->cancelPointer = $cancelPointer;
        $this->settings->skipToCustom = NULL;
        Log::addDebug("PAUSE: Pointer = " . $this->settings->cancelPointer);
        foreach ($this->get() as $qItem) {
            if ($qItem < $bulkStartId) {
                $this->remove($qItem);
            }
        }
        $this->stopBulk();
    }
    public function cancelBulk()
    {
        $this->pauseBulk();
        Log::addDebug("STOP, delete pointer.");
        $this->settings->cancelPointer = NULL;
    }
    public function stopBulk()
    {
        $this->settings->startBulkId = ShortPixelMetaFacade::getMaxMediaId();
        $this->settings->stopBulkId = $this->settings->startBulkId;
        $this->settings->bulkProcessingStatus = null;
        return $this->settings->bulkEverRan;
    }
    public function resumeBulk()
    {
        $this->settings->startBulkId = $this->settings->cancelPointer;
        $this->settings->stopBulkId = ShortPixelMetaFacade::getMinMediaId();
        $this->settings->bulkProcessingStatus = 'running';
        $this->settings->cancelPointer = null;
        WPShortPixel::log("Resumed: (pause says: " . $this->bulkPaused() . ") Start from: " . $this->settings->startBulkId . " to " . $this->settings->stopBulkId);
    }
    public function resetBulkCurrentlyProcessed()
    {
        $this->settings->bulkCurrentlyProcessed = 0;
    }
    public function incrementBulkCurrentlyProcessed()
    {
        $this->settings->bulkCurrentlyProcessed = $this->settings->bulkCurrentlyProcessed + 1;
    }
    public function markBulkComplete()
    {
        $this->settings->bulkProcessingStatus = null;
        $this->settings->cancelPointer = null;
    }
    public static function resetBulk()
    {
        delete_option('wp-short-pixel-bulk-type');
        delete_option('bulkProcessingStatus');
        delete_option('wp-short-pixel-cancel-pointer');
        delete_option("wp-short-pixel-flag-id");
        $startBulkId = $stopBulkId = ShortPixelMetaFacade::getMaxMediaId();
        update_option('wp-short-pixel-query-id-stop', $startBulkId, 'no');
        update_option('wp-short-pixel-query-id-start', $startBulkId, 'no');
        delete_option("wp-short-pixel-bulk-previous-percent");
        delete_option("wp-short-pixel-bulk-processed-items");
        delete_option('wp-short-pixel-bulk-running-time');
        delete_option('wp-short-pixel-last-bulk-start-time');
        delete_option('wp-short-pixel-last-bulk-success-time');
        delete_option("wp-short-pixel-bulk-processed-items");
        delete_option("wp-short-pixel-bulk-count");
        delete_option("wp-short-pixel-bulk-done-count");
    }
    public static function resetPrio()
    {
        self::set(array());
    }
    public function logBulkProgress()
    {
        $t = time();
        $this->incrementBulkCurrentlyProcessed();
        $successTime = $this->settings->lastBulkSuccessTime;
        if ($t - $successTime > 120) {
            $this->settings->bulkRunningTime += $successTime - $this->settings->lastBulkStartTime;
            $this->settings->lastBulkStartTime = $t;
            $this->settings->lastBulkSuccessTime = $t;
        } else {
            $this->settings->lastBulkSuccessTime = $t;
        }
    }
    public function getBulkPercent()
    {
        $previousPercent = $this->settings->bulkPreviousPercent;
        if ($this->getBulkToProcess() <= 0) {
            return $this->processing() ? 99 : 100;
        }
        $percent = $previousPercent + round($this->settings->bulkCurrentlyProcessed / $this->getBulkToProcess() * (100 - $previousPercent));
        return min(99, $percent);
    }
    public function getDeltaBulkPercent()
    {
        return $this->getBulkPercent() - $this->settings->bulkPreviousPercent;
    }
    public function getTimeRemaining()
    {
        $p = $this->getBulkPercent();
        $pAlready = $this->settings->bulkCount == 0 ? 0 : round($this->settings->bulkAlreadyDoneCount / $this->settings->bulkCount * 100);
        if ($p - $pAlready == 0) {
            return 0;
        }
        return round((100 - $p) / ($p - $pAlready) * ($this->settings->bulkRunningTime + $this->settings->lastBulkSuccessTime - $this->settings->lastBulkStartTime) / 60);
    }
}