使用com_joomlaupdate通过CLI升级Joomla

Tho*_*sen 5 joomla command-line-interface joomla-extensions joomla2.5 joomla3.0

我正在尝试编写一个Joomla CLI脚本,自动将站点升级到当前版本.在Joomla中,这似乎是通过*com_joomlaupdate*完成的.我们的想法是能够从管理员前端升级服务器上的任何Joomla站点.

我编写了以下内容进行测试,尝试通过直接访问其模型中的方法来模拟com_joomlaupdate中的控制器.我不熟悉joomla框架所以我可能在这里做一些愚蠢的事情.

<?php

const _JEXEC = 1;

error_reporting(E_ALL | E_NOTICE);
ini_set('display_errors', 1);

define('JPATH_BASE', dirname(__DIR__));

require_once JPATH_BASE . '/includes/defines.php';
require_once JPATH_BASE . '/includes/framework.php';

require_once JPATH_LIBRARIES . '/import.legacy.php';
require_once JPATH_LIBRARIES . '/cms.php';

// Load the configuration
require_once JPATH_CONFIGURATION . '/configuration.php';

define('JPATH_COMPONENT_ADMINISTRATOR', JPATH_ADMINISTRATOR . '/components/com_joomlaupdate');

require_once JPATH_COMPONENT_ADMINISTRATOR . '/models/default.php';

class Upgradejoomla extends JApplicationCli
{

        public function doExecute()
        {
                $app = JFactory::getApplication('administrator');
                $app->initialise();
                $app->input->set('method', 'direct');

                $this->out('Fetching updates...');

                $updater = JModelLegacy::getInstance('JoomlaupdateModelDefault');

                $updater->refreshUpdates();

                $updater->applyUpdateSite();

                $basename = $updater->download();

                $app->setUserState('com_joomlaupdate.file', $basename);

                $updater->createRestorationFile($basename);

                echo ($updater->finaliseUpgrade());

                $updater->cleanUp();
        }
}

JApplicationCli::getInstance('Upgradejoomla')->execute();
Run Code Online (Sandbox Code Playgroud)

download()工作正常,我得到最新的文件,并将其放在tmp目录中.createRestorationFile()似乎也工作,我在com_joomlaupdate目录中得到一个restoration.php文件.

问题似乎与finaliseUpgrade().它调用setupInstall()Installer,它试图查找清单文件.我错过了(除其他事项外)我认为这个文件(或更新的全部内容)在某处解压缩的步骤.问题是我找不到任何在com_joomlaupdate中执行此操作的代码?

我试图在/ tmp中手动解压缩更新文件.当我这样做,finaliseUpgrade()实际上返回true,但该网站仍然保持旧版本.

Tho*_*sen 0

好吧,我想通了。

部分更新是使用restore.php(显然取自Akeeba 备份)进行的。Joomla 对restore.php 进行了2 个ajax 调用,第一个返回一个工厂对象,您必须将其传回。还有 AES CTR 加密需要担心。我所做的是使用curl 来模仿Joomla 的ajax 调用。

这是当前的代码。它可能需要进行大量清理(不要对 URL 进行硬编码、更多错误检查等),但它确实有效。

const _JEXEC = 1;

error_reporting(E_ALL | E_NOTICE);
ini_set('display_errors', 1);

define('JPATH_BASE', dirname(__DIR__));

require_once JPATH_BASE . '/includes/defines.php';
require_once JPATH_BASE . '/includes/framework.php';

require_once JPATH_LIBRARIES . '/import.legacy.php';
require_once JPATH_LIBRARIES . '/cms.php';

// Load the configuration
require_once JPATH_CONFIGURATION . '/configuration.php';

define('JPATH_COMPONENT_ADMINISTRATOR', JPATH_ADMINISTRATOR . '/components/com_joomlaupdate');

require_once JPATH_COMPONENT_ADMINISTRATOR . '/models/default.php';

// restore.php is loud, using ob_end_clean() to shut it up, we need it for decryption
ob_start();
require_once JPATH_COMPONENT_ADMINISTRATOR . '/restore.php';
ob_end_clean();

class Upgradejoomla extends JApplicationCli
{

    // Used to talk to restore.php, since it only comunicates using Ajax.
    public function curlCall($data) {
        $url = 'http://localhost/administrator/components/com_joomlaupdate/restore.php';
        $ch = curl_init ($url);
        curl_setopt ($ch, CURLOPT_POST, true);
        curl_setopt ($ch, CURLOPT_POSTFIELDS, $data);
        curl_setopt ($ch, CURLOPT_RETURNTRANSFER, true);
        $ret = curl_exec ($ch);
        return $ret;
    }

    // Decrypt the JSON return.php passes back to us, and make it a php array while we're at it.
    public function deCrypt($str, $password) {
        $result = AKEncryptionAES::AESDecryptCtr($str, $password, 128);
        return json_decode($result, true);
    }

    public function doExecute() {
        // Get a Joomla-instance so createResorationFile() doesn't complain too much.
        $app = JFactory::getApplication('site');
        $app->initialise();
        // Make sure we're not in FTP mode
        $app->input->set('method', 'direct');

        // com_joomlaupdate's model
        $updater = JModelLegacy::getInstance('JoomlaupdateModelDefault');

        // Make sure we know what the latest version is
        $updater->refreshUpdates();
                $updater->applyUpdateSite();

        // Let's see if we're already on the latest version, the model always returns a null-object if this is the case
        $version_check = $updater->getUpdateInformation();
        if (is_null($version_check['object'])) {
            echo 'No new updates available' . "\n";
            return 0;
        }

        $this->out('Fetching updates...');

        // Grab the update (ends up in /tmp)
        $basename = $updater->download();

        // Create restoration.php (ends up in /com_joomlaupdate)
        $updater->createRestorationFile($basename);

        // Grab the password that was generated and placed in restoration.php so we can decrypt later
        $password = $app->getUserState('com_joomlaupdate.password', null);

        // Ask restore.php to start
        $first_pass = array (
            "task" => "startRestore",
        );

        $result = $this->curlCall($first_pass);
        $result = $this->deCrypt($result, $password);

        // Now we can pass back the factory-object we got and let restore.php do its thing
        $second_pass = array (
            "task" => "stepRestore",
            "factory" => $result['factory']
        );

        $result = $this->curlCall($second_pass);
        $result = $this->deCrypt($result, $password);

        if ($result['done'] == 1) {
            echo "Success!". "\n";
        }
        // Update SQL etc based on the manifest file we got with the update     
        $updater->finaliseUpgrade();

        $updater->cleanUp();
    }
}
JApplicationCli::getInstance('Upgradejoomla')->execute();
                                                             
Run Code Online (Sandbox Code Playgroud)