Viewing File: /usr/local/cpanel/3rdparty/wpinstaller/src/WpDownloader/Component/Base.php

<?php

namespace WpDownloader\Component;

use WpDownloader\Utility;
use WpDownloader\Log;

abstract class Base
{
    public $temporaryDirectory = '/tmp/wpinstaller';
    public $localPath; // Where the WP files are stored locally
    public $saveDataFile = '.wpdownloader.json'; // What file, inside the $localPath we will use to store data about this
    public $tempPath; // Where to put files before checksums are verified
    public $distPath = '/usr/local/cpanel/3rdparty/wpinstaller/files/plugins'; // Where we put files to be installed from
    public $version; // Holds the version number of the current component
    public $componentData; // Info about what the plugin is, where to obtain it, etc...
    public $slug; // Borrowing this term from the WP vocabulary; it is a way to identify a component.

    abstract public function getDestinationPath();

    public function cleanupTmp()
    {
        $tmp_dir = $this->temporaryDirectory;
        $files = scandir($this->temporaryDirectory);
        foreach ($files as $file) {
            if (preg_match('/\.tmp/', $file)) {
                $path = $tmp_dir . '/'. $file;
                Log::write("\tRemoving old temp file $path");
                unlink($path);
            }
        }
    }

    public function getSourcePath()
    {
        return "{$this->localPath}/{$this->getSlug()}";
    }

    public function getActivationFile()
    {
        return false;
    }

    public function isMuPlugin()
    {
        return false;
    }
    public function isPlugin()
    {
        return false;
    }

    public function getSlug()
    {
        return $this->slug;
    }

    public function thawLocalData()
    {
        $localDataFilePath = $this->getLocalDataFilePath();
        if (!file_exists($localDataFilePath)) {
            return [];
        }

        $localJson = file_get_contents($localDataFilePath);

        return json_decode($localJson, 1) ?: [];
    }

    public function getCurrentLocalVersion()
    {
        $data = $this->thawLocalData();

        if (empty($data['version'])) {
            return $this->getDefaultVersionNumber();
        }

        return $data['version'];
    }

    public function getDefaultVersionNumber()
    {
        return "0.0.0";
    }

    /**
     * Merges a new set of data into the existing JSON file, overwriting recursively if necessary.
     *
     * @param array  $toAppend  The new keys and values to merge into the existing saved JSON data
     */
    public function appendLocalData($toAppend)
    {
        $existingData = $this->thawLocalData();

        $newData = array_merge_recursive($existingData, $toAppend);

        $localDataFilePath = $this->getLocalDataFilePath();
        $result = file_put_contents($localDataFilePath, json_encode($newData, JSON_PRETTY_PRINT));

        if (!$result) {
            Log::throwException("Failed to save updated data to {$localDataFilePath}");
        }

        return $newData;
    }

    public function getLocalDataFilePath()
    {
        return "{$this->localPath}/{$this->saveDataFile}";
    }

    public function downloadFile($url, $file, $dlappend=null)
    {
        if ($dlappend===null) {
            $dlappend = gmdate("Y_m_d_h.i.s");
        }
        $tmp_file = $file . ".tmp." . $dlappend;

        $tmpDir = dirname($tmp_file);
        if (!is_dir($tmpDir)) {
            if (!mkdir($tmpDir, 0755, true)) {
                Log::throwException("[ERROR] Unable to create temporary download dir: {$tmpDir}");
            }
        }

        Log::write("\tAttemtping to download $url to $tmp_file");

        $fp = fopen($tmp_file, 'w');
        if (!$fp) {
            Log::throwException("[ERROR] Unable to acquire file handle for {$tmp_file}");
        }

        if (!flock($fp, LOCK_EX)) {
            Log::throwException("[ERROR] Unable to acquire flock for {$tmp_file}");
        }

        $ch = curl_init($url);

        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
        curl_setopt($ch, CURLOPT_TIMEOUT, 15);
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);

        curl_setopt($ch, CURLOPT_FILE, $fp);

        //$data = curl_exec($ch);
        $ret = curl_exec($ch);

        curl_close($ch);

        flock($fp, LOCK_UN);
        fclose($fp);

        if ($ret !== true) {
            Log::throwException("[ERROR] Unable to download $tmp_file");
            unlink($tmp_file);
            return $ret;
        }

        // Check if file is zip
        if (preg_match('/\.zip$/', $file)) {
            $ret = $this->verifyZipIntegrity($tmp_file);
        } else {
            // Do other checks
            Log::write("\t[WARN]\tNot a Zip file, skipping integrity check ($tmp_file)");
            $ret = true;
        }

        if ($ret !== true) {
            unlink($tmp_file);
            Log::throwException("[ERROR] Corrupt file $tmp_file");
        }

        if (rename($tmp_file, $file)) {
            Log::write("[OK]\t$tmp_file renamed to $file");
        } else {
            Log::throwException("[ERROR] failed to rename $tmp_file to $file");
        }

        if (!$file || !file_exists($file)) {
            Log::throwException("Downloaded failed or local file {$file} does not exist.");
        }

        return $file;
    }


    public function verifyZipIntegrity($file)
    {
        $zip = new \ZipArchive;
        $res = $zip->open($file, \ZIPARCHIVE::CHECKCONS);
        if ($res === true) {
            /*
                    for ($i = 0; $i < $zip->numFiles; $i++) {
                            $filename = $zip->getNameIndex($i);
                            Log::write($filename);
                    }
            */
            Log::write("[OK]\tZip integirty good ($res) ($file)");

            return $res;
        } else {
            Log::write("[ERROR]\tZip integirty issue ($res) ($file)");
            return $res;
        }
    }

    protected function extractArchive($inputFilePath)
    {
        Log::write("Opening archive {$inputFilePath}");

        $zip = new \ZipArchive;
        if (!$zip->open($inputFilePath)) {
            Log::throwException("Failed to open handle to zip file {$inputFilePath}");
        }

        if (!is_dir($this->tempPath)) {
            if (!mkdir($this->tempPath, 0755, true)) {
                Log::throwException("Failed to create temporary directory for extraction {$this->tempPath}");
            }
        }

        Log::write("Extracting {$inputFilePath} to {$this->tempPath}");

        $zip->extractTo($this->tempPath);
        $zip->close();

        return $this->tempPath;
    }

    public function commitTempToPersistent()
    {
        Log::write("Committing temp files {$this->tempPath} to persist at {$this->localPath}");

        if (file_exists($this->localPath) && is_dir($this->localPath)) {
            Log::write("Deleting directory {$this->localPath} to make room for new files.");
            Utility::deleteDirectory($this->localPath);
        }
        return rename($this->tempPath, $this->localPath);
    }


    public function hasUpdateAvailable()
    {
        $localVersion = $this->getCurrentLocalVersion();
        $remoteVersion = $this->getLatestVersion();

        Log::write("Local version: $localVersion Remote version: $remoteVersion. Slug: {$this->getSlug()}");

        return version_compare($localVersion, $remoteVersion, '<');
    }

    public function setData($data)
    {
        $this->componentData = $data;

        $this->afterSetData();
    }

    public function afterSetData()
    {
        return true;
    }
}
Back to Directory File Manager