HEX
Server: Apache/2.4.63 (Unix)
System: Linux TOMS-220NAS 4.4.302+ #86009 SMP Wed Nov 26 18:19:17 CST 2025 x86_64
User: flavio87 (1026)
PHP: 8.3.27
Disabled: NONE
Upload Files
File: /volume1/web/tom-marchisa/wp-content/plugins/real-physical-media/inc/queue/Row.php
<?php

namespace DevOwl\RealPhysicalMedia\queue;

use DevOwl\RealPhysicalMedia\base\UtilsProvider;
use DevOwl\RealPhysicalMedia\handler\Handler;
use DevOwl\RealPhysicalMedia\misc\Seo;
use DevOwl\RealPhysicalMedia\misc\UploadDir;
use DevOwl\RealPhysicalMedia\Util;
use ErrorException;
use Exception;
\defined('ABSPATH') or die('No script kiddies please!');
// Avoid direct file request
/**
 * Queue item model.
 * @internal
 */
class Row
{
    use UtilsProvider;
    public $id;
    public $processId;
    public $attachment;
    public $loaded;
    public $total;
    public $created;
    public $logId;
    public $cleanupPath;
    public $currentFolderId;
    public $filename;
    public $sourceAbsPath;
    public $sourcePath;
    public $destinationPath;
    public $destinationPathRelativeUploadDir;
    private $destroyed = \false;
    private $previousUrls;
    /**
     * C'tor.
     *
     * @param int $id
     * @param string $processId
     * @param int $attachment
     * @param int $loaded
     * @param int $total
     * @param int $created
     * @param int $logId
     * @param string $cleanupPath
     * @param int $currentFolderId
     * @param string $filename
     * @param string $previousUrls
     */
    public function __construct($id, $processId, $attachment, $loaded, $total, $created, $logId, $cleanupPath, $currentFolderId, $filename, $previousUrls)
    {
        $this->id = (int) $id;
        $this->processId = $processId;
        $this->attachment = (int) $attachment;
        $this->loaded = (int) $loaded;
        $this->total = (int) $total;
        $this->created = (int) $created;
        $this->logId = $logId === null ? null : (int) $logId;
        $this->cleanupPath = $cleanupPath;
        $this->currentFolderId = (int) $currentFolderId;
        $this->filename = $filename;
        $this->previousUrls = $previousUrls;
    }
    /**
     * Process this single item and when done remove from queue and create log.
     *
     * @throws Exception
     */
    public function process()
    {
        global $wpdb;
        // Get current path
        $pathes = UploadDir::getInstance()->pathes($this->attachment, $this->getFolder());
        if ($pathes !== \false) {
            $this->sourceAbsPath = $pathes['sourceAbsPath'];
            $this->sourcePath = $pathes['sourcePath'];
            $this->destinationPath = $pathes['destinationPath'];
            $this->destinationPathRelativeUploadDir = $pathes['destinationPathRelativeUploadDir'];
        } else {
            // File perhaps deleted?
            $this->remove();
        }
        $instance = Handler::getInstance()->getCurrentInstance();
        if ($instance === null) {
            return \false;
        }
        // Check if already done
        if ($this->isDone()) {
            $this->remove();
            return \true;
        }
        // Skip this one with a filter
        try {
            /**
             * Allows to skip an attachment in the queue - it will not be moved. Simply
             * add_action and throw an exception to skip it.
             *
             * @param {int} $attachment Attachment id
             * @throws Exception
             * @hook RPM/Queue/Skip
             */
            \do_action('RPM/Queue/Skip', $this->attachment);
        } catch (Exception $e) {
            $this->remove();
            return \true;
        }
        // Process the rename
        $start = \microtime(\true) * 1000;
        // Save previous urls to database
        if ($this->logId === null && $this->loaded === 0) {
            // Use base64 encoding to avoid url replace of S&R plugins
            $this->previousUrls = \base64_encode(\json_encode($this->fetchUrls(\true)));
            $wpdb->update($this->getTableName('queue'), ['previousUrls' => $this->previousUrls], ['id' => $this->id]);
        }
        // Process with given error handler
        try {
            \set_error_handler([$this, 'set_error_handler']);
            $instance->process($this);
            \restore_error_handler();
        } catch (Exception $e) {
            \restore_error_handler();
            throw $e;
        }
        $done = $this->isDone();
        // Log and remove
        \clean_post_cache($this->attachment);
        // Clean cache so the URLs get updated properly
        $newUrls = $this->fetchUrls();
        if ($done) {
            $instance->finish($this);
            $this->remove($newUrls);
        }
        // Get the duration in milliseconds
        $duration = \microtime(\true) * 1000 - $start;
        $ms = $this->logger($duration);
        // Prepare the response with further details
        $newUrls['f'] = $this->filename;
        $newUrls['d'] = $this->destinationPath;
        $newUrls['ms'] = $ms;
        return $newUrls;
    }
    /**
     * Set error handler.
     *
     * @param string $errno
     * @param string $errstr
     * @param string $errfile
     * @param int $errline
     * @param string $errcontext
     * @see https://stackoverflow.com/a/1241751/5506547
     * @throws ErrorException
     */
    public function set_error_handler($errno, $errstr, $errfile, $errline, $errcontext = [])
    {
        // error was suppressed with the @-operator
        if (0 === \error_reporting()) {
            return \false;
        }
        if (!Handler::getInstance()->getCurrentInstance()) {
            // phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped -- Error details are wrapped in exception, not rendered output.
            throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
        }
    }
    /**
     * Fetch result for REST response.
     *
     * @param boolean $commonPrefix If true the result array is compressed to the common prefix
     */
    public function fetchUrls($commonPrefix = \false)
    {
        $image_metadata = \wp_get_attachment_metadata($this->attachment);
        $url = \wp_get_attachment_url($this->attachment);
        $result = [
            'i' => \false,
            // Defines if image
            'fid' => $this->currentFolderId,
            // The current folder id
            'u' => [
                // All urls including full and image sizes
                'full' => $url,
            ],
        ];
        if ($image_metadata !== \false) {
            $result['i'] = \true;
            if (isset($image_metadata['sizes'])) {
                foreach ($image_metadata['sizes'] as $key => $size) {
                    $sizeSrc = \wp_get_attachment_image_src($this->attachment, $key);
                    if ($sizeSrc !== \false) {
                        $result['u'][$key] = $sizeSrc[0];
                    }
                }
            }
        }
        // Find common prefix
        if ($commonPrefix) {
            $prefix = Util::commonPrefix(\array_values($result['u']));
            $prefln = \strlen($prefix);
            foreach ($result['u'] as $key => $u) {
                $result['u'][$key] = \substr($u, $prefln);
            }
            $result['p'] = $prefix;
        }
        return $result;
    }
    /**
     * Update the processLoaded in database.
     *
     * @param int $to The processLoaded value otherwise +1
     */
    public function progress($to = null)
    {
        global $wpdb;
        if ($to === null) {
            ++$this->loaded;
        } else {
            $this->loaded = \intval($to);
        }
        $wpdb->update($this->getTableName('queue'), ['processLoaded' => $this->loaded], ['id' => $this->id], '%d', '%d');
    }
    /**
     * Add queue item to logger.
     *
     * @param int $duration The duration in ms
     * @returns int The complete duration in ms
     */
    private function logger($duration)
    {
        global $wpdb;
        // If there is already a log increase the duration, only
        $table_name = $this->getTableName('log');
        $doneInt = $this->isDone() ? 1 : 0;
        if ($this->logId === null) {
            $wpdb->insert($table_name, ['attachment' => $this->attachment, 'duration' => $duration, 'done' => $doneInt, 'fromPath' => $this->sourcePath, 'toPath' => $this->destinationPath], ['%d', '%d', '%d', '%s', '%s']);
            // Save to the queue
            $this->logId = $wpdb->insert_id;
            $wpdb->update($this->getTableName('queue'), ['log' => $this->logId], ['id' => $this->id], '%d', '%d');
            \DevOwl\RealPhysicalMedia\queue\Queue::getInstance()->clearLog($this->logId);
            return $duration;
        } else {
            // phpcs:disable WordPress.DB.PreparedSQL
            $wpdb->query('UPDATE ' . $table_name . '
                SET duration = (duration + ' . \intval($duration) . '),
                    done = ' . $doneInt . '
                WHERE id = ' . $this->logId);
            return (int) $wpdb->get_var($wpdb->prepare('SELECT duration FROM ' . $table_name . ' WHERE id = %d', $this->logId));
            // phpcs:enable WordPress.DB.PreparedSQL
        }
    }
    /**
     * Remove the row from queue.
     *
     * @param array $newUrls Save data to the seo database table
     * @returns int Result of $wpdb->delete()
     */
    private function remove($newUrls = \false)
    {
        global $wpdb;
        $previousUrls = $this->getPreviousUrls();
        Seo::getInstance()->persistUrls($this->attachment, $previousUrls, $newUrls);
        $this->destroyed = \true;
        return $wpdb->delete($this->getTableName('queue'), ['id' => $this->id]);
    }
    /**
     * Checks if the row is done.
     *
     * @returns boolean
     */
    public function isDone()
    {
        return $this->loaded >= $this->total || $this->sourcePath === $this->destinationPath || $this->destroyed || empty($this->filename);
        // No physical file in database
    }
    /**
     * Checks if the file exists.
     *
     * @returns boolean
     */
    public function exists()
    {
        return \file_exists(\trailingslashit($this->sourceAbsPath) . $this->filename);
    }
    /**
     * Get the RML folder object for this row.
     *
     * @returns \MatthiasWeb\RealMediaLibrary\api\IFolder
     */
    public function getFolder()
    {
        return wp_rml_get_object_by_id($this->currentFolderId);
    }
    /**
     * Get previous urls of this row.
     *
     * @param boolean $parse
     */
    public function getPreviousUrls($parse = \true)
    {
        $p = $this->previousUrls;
        if ($parse && !empty($p)) {
            $p = \json_decode(\base64_decode($p), ARRAY_A);
            $prefix = $p['p'];
            unset($p['p']);
            foreach ($p['u'] as $key => $url) {
                $p['u'][$key] = $prefix . $url;
            }
        }
        return $p;
    }
}