5

我正在尝试编写一个自动将站点升级到当前版本的 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();

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

问题似乎与finaliseUpgrade(). 它调用setupInstall()安装程序,尝试查找清单文件。我想我缺少的(除其他外)是该文件(或更新的全部内容)在某处解压缩的步骤。问题是我在 com_joomlaupdate 中找不到任何代码?

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

4

3 回答 3

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();
                                                             
于 2013-08-21T21:39:52.090 回答
0

好吧,这肯定行不通:

wget -O j3.zip \
    https://github.com/joomla/joomla-cms/releases/download/3.3.6/Joomla_3.3.6-Stable-Full_Package.zip
unzip -o j3.zip

这对于以前版本的 joomla 非常有效:(

于 2015-01-14T14:20:14.197 回答
-1

我对此更新脚本感兴趣。在您更新的清单中,缺少“class Upgradejoomla extends JApplicationCli”之后的左括号,因此发生了错误。我已经对其进行了测试并放入了一些用于输出状态行的行。它使用 joomla 3.4.0 更新到 3.4.6 进行测试。下载到 /tmp 正在运行,但之后出现状态行但没有任何反应。我放入了一些 $_SERVER 变量以防止 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';

// 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();

$_SERVER['HTTP_HOST'] = 'http://domainname.de';
$_SERVER['REQUEST_URI'] = '/administrator/components/com_joomlaupdate/restore.php';
$_SERVER['PHP_SELF'] = '/administrator/components/com_joomlaupdate/restore.php';

class Upgradejoomla extends JApplicationCli
        {


        // Used to talk to restore.php, since it only comunicates using Ajax.
        public function curlCall($data) {


                $url = 'http://domainname.de/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);
                $this->out('creating restoration...');

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


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

                $this->out('start restore...');

                $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']
                );
                $this->out('pass factory object...');


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

                if($result['done'] == 1) {
                        echo "Success!". "\n";
                }
                $this->out('sucess...');

                // Update SQL etc based on the manifest file we got with the update
                $updater->finaliseUpgrade();
                $this->out('finalize...');

                $updater->cleanUp();
                $this->out('cleanup...');

        }
}


JApplicationCli::getInstance('Upgradejoomla')->execute();

?>

于 2015-12-17T10:19:59.813 回答