Joomla и имитация админа


Мне с детства не нравится джумла. Да, распространенная CMS, да много дополнений, да, на ней много можно сделать. Но очень неудобно доделывать что-то своё, что не предусмотрено штатным функционалом. Да еще на старых версиях. Однако есть заказчики с этой кмс и с интересными заказами. Об одном из них ниже я немного и расскажу.

  • Цель
  • Декомпозиция
  • Попытка номер 1
  • Попытка номер 2
  • Реализация
  • Итог
Цель

Необходимо сделать так, чтобы в Joomla 3 выполнялись автоматически действия с некоторыми заказами из компонента Jshopping в определенное время. Пройтись по заказам, найти с необходимым статусом, узнать трек-номер из СДЭК, затем изменить статус и отправить сообщение покупателю.



Звучит просто, верно? Ну если просто, то сразу делаем декомпозицию задачи.

Декомпозиция

Делим задачу на подзадачи

  1. Авторизация
  2. Получение заказов
  3. Получение трек номера от сдэк
  4. Изменение статуса и отправка комментария
Самым сложным мне тут подумалось, что будет получение трек-номера от сдек, но все получилось относительно просто (была пара нюансов, о которых расскажу в другой заметке, но целом все ок) – с него я и начал.

Сделал, дальше авторизовался админом и начал делать изменение статуса. Получение всех заказов по статусу оставил на конец – тут можно реализовать прямо через базу, даже не трогая джумлу.

Так что научимся менять статус заказа и всё можно будет собирать.

Попытка номер 1

Для начала авторизация, тут все оказалось очень просто, вариантов масса, например вот так

define('_JEXEC', 1);
define('JPATH_BASE', realpath(dirname(__FILE__)));
require_once JPATH_BASE . '/includes/defines.php';
require_once JPATH_BASE . '/includes/framework.php';
// Инициализация приложения
$app = JFactory::getApplication('site');
$app->initialise();
// Авторизация под администратором
$credentials = array(
	'username' => $username, 
	'password' => $pass
);
$app->login($credentials);
// Проверка, авторизован ли пользователь
if (!JFactory::getUser()->authorise('core.manage')) {
    echo "Ошибка: Пользователь не авторизован как администратор.\n";
    exit;
}
А вот что дальше? А дальше нам надо подключить нужный файл, создать экземпляр класса и вызвать нужную функцию. Потом повторить это для всех действий. Это на самом деле просто, но не в джумле.

Самый правильный способ – это подключить нужные пространства имен и классы, затем вызвать – и всё через встроенные функции джумлы 3. Пробуем

//подключаем компонент
 $component = JComponentHelper::getComponent('com_jshopping');
// Путь к компоненту
$componentPath = JPATH_BASE . '/components/com_jshopping';
// Подключаем автозагрузчик классов Joomla
JLoader::registerNamespace('Joomla\\Component\\Jshopping', $componentPath . '');
// Подключаем файл с классом, если он не подключен автоматически
JLoader::register('jshopOrderChangeStatus', $componentPath . '/models/orderchangestatus.php');
// Создаем экземпляр класса
$model = new jshopOrderChangeStatus();
// Вызываем метод класса
//$result = $model->someMethod();
В итоге – ошибка 404. Я подключал по-разному, пробовал в CLI (так в общем и надо) – не получается. Если вот так

define('JPATH_COMPONENT_SITE', JPATH_BASE."/ components/com_jshopping");
	require_once JPATH_BASE . '/administrator/components/com_jshopping/jshopping.php';
	require_once JPATH_BASE . '/administrator/components/com_jshopping/controllers/orders.php';
	$controller = new JshoppingControllerOrders();
	$controller->cront();
Тоже куча разных ошибок.

Скорее всего тут надо до подключения основного класса (в котором предполагалось работать) – надо подключить кучу дополнительных. Но проблема в том, что файлы с классами называются как угодно, а не как классы – то есть пройтись по всем рекурсивно зависимостям также не получится.

Тут мне надоело разгребать ошибки и я отложил решение задачи на следующий день.

Попытка номер 2

После множество попыток и совещаний с LLM, я не выдержал и просто решил отказаться от этой идеи – работы внутри. И стал делать снаружи.

Сначала опять же авторизуемся, переходим на страницу нужную и отправляем запрос имитируя форму, благо есть подобный инструмент у джумлы – JHttp. Набросал простейший пример

// Переход к определенной странице в админке
$url = 'index.php?option=com_yourcomponent&view=yourview&layout=edit&id=1';
$app->redirect($url);

// Заполнение формы
$http = new JHttp();
$postData = array(
    'jform[field1]' => 'value1',
    'jform[field2]' => 'value2',
    // Добавьте остальные поля формы
    'task' => 'yourtask.save', // Замените на нужный таск
    JSession::getFormToken() => 1 // Добавьте токен формы
);

$response = $http->post($url, $postData);

if ($response->code == 200) {
    echo "Форма успешно заполнена и сохранена.\n";
} else {
    echo "Ошибка: Не удалось заполнить форму.\n";
}
И… нет. После перехода на страницу все обрывается. В общем, логично, после редиректа – прерывает работу. Оставляем только авторизацию и потом сразу отправляем запрос. И … и ничего.

Реализация

Тут я окончательно не выдержал и набросал свой код отправки через curl php (после авторизации)

$url = 'http://домен /administrator/index.php?option=com_jshopping&controller=orders';

$postData = array(
    'order_id' => $order_id,
	'order_status' => $order_status,
	'comments' => $comment,
	'task' => 'update_one_status',
	'js_nolang' => '1'
);

$ch = curl_init($url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_COOKIE, session_name() . '=' . session_id());
$response = curl_exec($ch);
curl_close($ch);
И всё заработало

Итог

Да, я знаю, что так как я сделал – это не самый профессиональный путь, по учебнику надо было добиваться первого пути, но работает же?

Бесплатный совет – не заводите сайт на джумле, если в дальнейшем планируете свою кастомизацию. Или запасайтесь терпением при изменениях или ищите хорошего программиста.
Автор этого материала - я - Пахолков Юрий. Я оказываю услуги по написанию программ на языках Java, C++, C# (а также консультирую по ним) и созданию сайтов. Работаю с сайтами на CMS OpenCart, WordPress, ModX и самописными. Кроме этого, работаю напрямую с JavaScript, PHP, CSS, HTML - то есть могу доработать ваш сайт или помочь с веб-программированием. Пишите сюда.

тегизаметки, Joomla, php




Отправляя сообщение я подтверждаю, что ознакомлен и согласен с политикой конфиденциальности данного сайта.




Основы модульного тестирования на PHP
Дженерики (Generics) в Java
Именование томов Windows