Интернет-магазин на OpenCart
Пошаговое руководство по установке, настройке и интеграции всех необходимых модулей для работы магазина в России: оплата, доставка, онлайн-касса, Честный знак.
Архитектура решения
Общая схема интеграций интернет-магазина
Системные требования
Что нужно для установки и стабильной работы OpenCart
Минимальные требования
Для небольшого магазина до 1000 товаров
- PHP 8.1 или выше
- MySQL 5.7+ / MariaDB 10.3+
- Apache 2.4+ или Nginx
- RAM: 2 GB минимум
- Диск: 10 GB SSD
- SSL-сертификат (Let's Encrypt)
Рекомендуемые требования
Для магазина от 5000+ товаров
- PHP 8.2+ с OPcache
- MySQL 8.0 / MariaDB 10.6+
- Nginx + PHP-FPM
- RAM: 4-8 GB
- Диск: 50+ GB NVMe SSD
- Redis для кэширования
Необходимые PHP-расширения
# Обязательные расширения для OpenCart 4.x extension=curl extension=gd extension=mbstring extension=mysqli extension=openssl extension=zip extension=zlib extension=xml extension=intl # Рекомендуемые настройки memory_limit = 256M upload_max_filesize = 50M post_max_size = 50M max_execution_time = 300 max_input_vars = 5000 # OPcache для производительности opcache.enable=1 opcache.memory_consumption=256 opcache.max_accelerated_files=10000 opcache.validate_timestamps=0
Для российского магазина выбирайте хостинг с серверами в РФ: Timeweb, REG.ru, Beget. Это обеспечит быструю загрузку и соответствие 152-ФЗ о персональных данных.
Установка OpenCart
Пошаговая инструкция по установке на сервер
Загрузите последнюю версию с официального сайта или GitHub:
# Скачиваем OpenCart 4.0.2.3 cd /var/www/html wget https://github.com/opencart/opencart/releases/download/4.0.2.3/opencart-4.0.2.3.zip unzip opencart-4.0.2.3.zip mv opencart-4.0.2.3/upload/* ./ rm -rf opencart-4.0.2.3 opencart-4.0.2.3.zip
-- Создаём базу данных и пользователя CREATE DATABASE opencart_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; CREATE USER 'opencart_user'@'localhost' IDENTIFIED BY 'Secure_Password_123!'; GRANT ALL PRIVILEGES ON opencart_db.* TO 'opencart_user'@'localhost'; FLUSH PRIVILEGES;
# Права на файлы и папки chown -R www-data:www-data /var/www/html find /var/www/html -type d -exec chmod 755 {} \; find /var/www/html -type f -exec chmod 644 {} \; # Создаём конфиг файлы cp config-dist.php config.php cp admin/config-dist.php admin/config.php chmod 777 config.php admin/config.php # Права на папки для записи chmod -R 777 image/ chmod -R 777 image/cache/ chmod -R 777 image/catalog/ chmod -R 777 system/storage/
Откройте в браузере: https://your-domain.ru/install/
Следуйте инструкциям мастера установки:
- Проверка требований системы
- Ввод данных базы данных
- Создание администратора
- Завершение установки
# ВАЖНО! Удалите после установки rm -rf /var/www/html/install/ # Верните права на конфиг файлы chmod 644 config.php admin/config.php
Для автоматизации развертывания можно использовать CLI-установку.
# CLI установка OpenCart php install/cli_install.php install \ --db_hostname localhost \ --db_username opencart_user \ --db_password Secure_Password_123! \ --db_database opencart_db \ --db_driver mysqli \ --db_port 3306 \ --username admin \ --password admin_password \ --email admin@yoursite.ru \ --http_server https://yoursite.ru/
Docker идеален для локальной разработки и тестирования. Для продакшена рекомендуем традиционную установку.
version: '3.8' services: opencart: image: bitnami/opencart:4 container_name: opencart ports: - "80:8080" - "443:8443" environment: - OPENCART_HOST=localhost - OPENCART_DATABASE_HOST=mariadb - OPENCART_DATABASE_PORT_NUMBER=3306 - OPENCART_DATABASE_USER=opencart_user - OPENCART_DATABASE_PASSWORD=opencart_pass - OPENCART_DATABASE_NAME=opencart_db - OPENCART_USERNAME=admin - OPENCART_PASSWORD=admin_password - OPENCART_EMAIL=admin@yoursite.ru volumes: - 'opencart_data:/bitnami/opencart' depends_on: - mariadb mariadb: image: mariadb:10.6 container_name: opencart_db environment: - MYSQL_ROOT_PASSWORD=root_password - MYSQL_DATABASE=opencart_db - MYSQL_USER=opencart_user - MYSQL_PASSWORD=opencart_pass volumes: - 'mariadb_data:/var/lib/mysql' redis: image: redis:7-alpine container_name: opencart_redis volumes: opencart_data: mariadb_data:
# Запуск контейнеров docker-compose up -d # Проверка статуса docker-compose ps # Логи docker-compose logs -f opencart
Конфигурация Nginx
server { listen 80; server_name yoursite.ru www.yoursite.ru; return 301 https://$server_name$request_uri; } server { listen 443 ssl http2; server_name yoursite.ru www.yoursite.ru; root /var/www/html; index index.php index.html; # SSL сертификаты (Let's Encrypt) ssl_certificate /etc/letsencrypt/live/yoursite.ru/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/yoursite.ru/privkey.pem; ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256; # Безопасность add_header X-Frame-Options "SAMEORIGIN" always; add_header X-Content-Type-Options "nosniff" always; add_header X-XSS-Protection "1; mode=block" always; # Gzip сжатие gzip on; gzip_types text/plain text/css application/json application/javascript text/xml application/xml; gzip_min_length 1000; # Основной location location / { try_files $uri $uri/ @opencart; } location @opencart { rewrite ^/(.+)$ /index.php?_route_=$1 last; } # Обработка PHP location ~ \.php$ { fastcgi_pass unix:/var/run/php/php8.2-fpm.sock; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; fastcgi_buffer_size 128k; fastcgi_buffers 256 16k; } # Статика - кэширование location ~* \.(jpg|jpeg|png|gif|ico|css|js|svg|woff|woff2)$ { expires 30d; add_header Cache-Control "public, immutable"; } # Запрет доступа к служебным файлам location ~ /\.(htaccess|git|env) { deny all; } location ~ /(system|admin/controller|admin/model|admin/view|catalog/controller|catalog/model) { deny all; } }
Базовая настройка магазина
Конфигурация магазина, валюты, языки, налоги
Настройки магазина
Система → Настройки → Магазин
- Название: Ваш магазин
- Владелец: ООО/ИП название
- Адрес: Юридический адрес
- Email: info@yoursite.ru
- Телефон: +7 (XXX) XXX-XX-XX
- Формат изображений: WebP
Локализация
Система → Локализация
- Страна: Россия
- Регион: Ваш регион
- Язык: Русский
- Валюта: Российский рубль (₽)
- Единицы измерения: Метрическая
- Формат даты: d.m.Y
Настройка валюты
Настройки для Российского рубля: Название: Российский рубль Код: RUB Символ слева: (оставить пустым) Символ справа: ₽ Десятичных: 2 Курс: 1.00000000 Статус: Включено По умолчанию: Да
Настройка налогов (НДС)
Настройка налогов зависит от вашей системы налогообложения (ОСНО, УСН, ПСН). При УСН без НДС выбирайте ставку НДС 0% или "Без НДС".
| Налоговый класс | Ставка | Применение |
|---|---|---|
| НДС 20% | 20% | Стандартные товары (ОСНО) |
| НДС 10% | 10% | Продукты, детские товары, книги |
| НДС 0% | 0% | Экспорт, УСН |
| Без НДС | — | УСН, ПСН (не плательщики НДС) |
-- Добавляем налоговые ставки для России -- Налоговый класс НДС 20% INSERT INTO `oc_tax_class` (`tax_class_id`, `title`, `description`) VALUES (1, 'НДС 20%', 'Стандартная ставка НДС'); -- Налоговая ставка INSERT INTO `oc_tax_rate` (`tax_rate_id`, `geo_zone_id`, `name`, `rate`, `type`) VALUES (1, 0, 'НДС 20%', 20.0000, 'P'); -- Связь класса и ставки INSERT INTO `oc_tax_rule` (`tax_class_id`, `tax_rate_id`, `based`, `priority`) VALUES (1, 1, 'shipping', 1);
Статусы заказов
Управление товарами
Структура каталога, категории, атрибуты, импорт
Структура каталога
Создание товара
Основные данные
Вкладка "Основное"
- Название: Название товара
- Мета-тег Title: SEO заголовок
- Мета-тег Description: SEO описание
- Тег товара: Ключевые слова
- Описание: Полное описание
Данные товара
Вкладка "Данные"
- Модель: Артикул / SKU
- Цена: Розничная цена
- Количество: Остаток на складе
- Статус: Есть в наличии
- Налоговый класс: НДС 20%
Важные поля для маркировки (Честный знак)
Для товаров, подлежащих маркировке (одежда, обувь, парфюмерия, шины и др.), необходимо хранить коды маркировки Data Matrix.
-- Добавляем поля для маркировки в таблицу товаров ALTER TABLE `oc_product` ADD COLUMN `gtin` VARCHAR(14) DEFAULT NULL COMMENT 'GTIN/EAN код', ADD COLUMN `marking_type` VARCHAR(50) DEFAULT NULL COMMENT 'Тип маркировки', ADD COLUMN `tnved_code` VARCHAR(20) DEFAULT NULL COMMENT 'Код ТН ВЭД'; -- Таблица для хранения кодов маркировки (Data Matrix) CREATE TABLE `oc_product_marking` ( `marking_id` INT(11) NOT NULL AUTO_INCREMENT, `product_id` INT(11) NOT NULL, `order_id` INT(11) DEFAULT NULL, `marking_code` VARCHAR(150) NOT NULL COMMENT 'Код Data Matrix', `status` ENUM('available', 'reserved', 'sold', 'returned') DEFAULT 'available', `date_added` DATETIME NOT NULL, `date_sold` DATETIME DEFAULT NULL, PRIMARY KEY (`marking_id`), KEY `product_id` (`product_id`), KEY `order_id` (`order_id`), UNIQUE KEY `marking_code` (`marking_code`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
Массовый импорт товаров
Формат CSV файла для импорта товаров:
product_id;name;model;sku;price;quantity;category;image;description;gtin;weight;status ;Смартфон iPhone 15;IPHONE15;APL-IP15-128;89990;50;Электроника > Смартфоны;iphone15.jpg;Описание товара;4680001234567;0.171;1 ;Ноутбук MacBook Air;MBA-M2;APL-MBA-M2;119990;25;Электроника > Ноутбуки;macbook.jpg;Описание ноутбука;4680009876543;1.24;1 ;Футболка мужская;TSHIRT-M-BLK;TSH-001;1990;100;Одежда > Мужская;tshirt.jpg;Хлопок 100%;4680005551234;0.15;1
Import/Export Tool: Бесплатный базовый импорт
CSV Price Pro: Расширенный импорт с обновлением цен (~2000₽)
Import PRO: Профессиональный импорт с CRON (~5000₽)
Интеграция с 1С через CommerceML:
Настройки модуля обмена с 1С: URL обмена: https://yoursite.ru/index.php?route=extension/module/exchange1c Логин: admin Пароль: ваш_пароль Формат: CommerceML 2.10 Кодировка: UTF-8 Параметры синхронизации: Импорт товаров: Да Импорт цен: Да Импорт остатков: Да Экспорт заказов: Да Интервал: Каждые 30 минут
Импорт товаров через REST API:
<?php // Импорт товара через OpenCart API $api_url = 'https://yoursite.ru/index.php?route=api/product/add'; $api_token = 'your_api_token'; $product_data = [ 'name' => 'Новый товар', 'model' => 'MODEL-001', 'sku' => 'SKU-001', 'price' => 9990, 'quantity' => 100, 'status' => 1, 'category_id' => [25], 'description' => 'Описание товара', 'meta_title' => 'Новый товар - купить', 'gtin' => '4680001234567', 'weight' => 0.5, 'tax_class_id' => 1 ]; $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $api_url); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($product_data)); curl_setopt($ch, CURLOPT_HTTPHEADER, [ 'Authorization: Bearer ' . $api_token ]); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = curl_exec($ch); curl_close($ch); $result = json_decode($response, true); print_r($result);
Модули оплаты
Интеграция ЮKassa, Робокасса, T-Pay
ЮKassa
Яндекс.Касса
Популярная платёжная система. Карты, СБП, электронные кошельки.
- Комиссия от 2.8%
- СБП (0% комиссии)
- Возвраты онлайн
- Официальный модуль
Робокасса
Robokassa
Множество способов оплаты. Подходит для ИП и самозанятых.
- Комиссия от 2.3%
- 40+ способов оплаты
- Быстрое подключение
- Работа с самозанятыми
T-Pay
Тинькофф
Интернет-эквайринг от Тинькофф. Быстрое подключение.
- Комиссия от 2.49%
- Выплаты на следующий день
- Рекуррентные платежи
- API и виджеты
🔧 Настройка ЮKassa
Зарегистрируйтесь на yookassa.ru и получите:
- shopId — идентификатор магазина
- Секретный ключ API
Скачайте официальный модуль с GitHub или маркетплейса OpenCart.
# Клонируем модуль ЮKassa cd /var/www/html git clone https://github.com/yoomoney/yookassa-cms-opencart.git cp -r yookassa-cms-opencart/src/upload/* ./ # Или установка через админку: # Расширения → Установка расширений → Загрузить файл .ocmod.zip
Расширения → Оплата → ЮKassa Shop ID: 123456 Секретный ключ: live_xxxxxxxxxxxxxxxxxxxxx Режим работы: Боевой (или Тестовый) --- Способы оплаты --- Банковские карты: Включено ЮMoney: Включено СБП: Включено Кредит/Рассрочка: По желанию --- Фискализация --- Отправка чеков: Включено Система налогообложения: УСН доходы (или ваша) НДС по умолчанию: Без НДС --- Уведомления --- URL для уведомлений: https://yoursite.ru/index.php?route=extension/payment/yookassa/callback Статус после оплаты: Оплачен
🔧 Настройка Робокасса
Расширения → Оплата → Робокасса Логин магазина: your_shop_login Пароль #1: password1_for_requests Пароль #2: password2_for_callback --- В личном кабинете Робокассы --- Result URL: https://yoursite.ru/index.php?route=extension/payment/robokassa/callback Success URL: https://yoursite.ru/index.php?route=extension/payment/robokassa/success Fail URL: https://yoursite.ru/index.php?route=extension/payment/robokassa/fail Метод отправки: POST Алгоритм хеширования: SHA256 --- Фискализация (если нужна) --- Отправка чеков: Включено СНО: usn_income (УСН доходы)
🔧 Настройка T-Pay (Тинькофф)
<?php // catalog/controller/extension/payment/tinkoff.php namespace Opencart\Catalog\Controller\Extension\Payment; class Tinkoff extends \Opencart\System\Engine\Controller { private $terminal_key; private $secret_key; private $api_url = 'https://securepay.tinkoff.ru/v2/'; public function index(): string { $this->load->language('extension/payment/tinkoff'); $data['action'] = $this->url->link('extension/payment/tinkoff|confirm'); return $this->load->view('extension/payment/tinkoff', $data); } public function confirm(): void { $this->load->model('checkout/order'); $order_info = $this->model_checkout_order->getOrder( $this->session->data['order_id'] ); $params = [ 'TerminalKey' => $this->config->get('payment_tinkoff_terminal_key'), 'Amount' => round($order_info['total'] * 100), 'OrderId' => $order_info['order_id'], 'Description' => 'Заказ #' . $order_info['order_id'], 'DATA' => [ 'Email' => $order_info['email'], 'Phone' => $order_info['telephone'] ], 'Receipt' => $this->getReceipt($order_info) ]; $params['Token'] = $this->generateToken($params); $response = $this->sendRequest('Init', $params); if ($response['Success']) { $this->response->redirect($response['PaymentURL']); } } private function getReceipt($order_info): array { // Формируем чек для фискализации $items = []; foreach ($this->cart->getProducts() as $product) { $items[] = [ 'Name' => $product['name'], 'Price' => round($product['price'] * 100), 'Quantity' => $product['quantity'], 'Amount' => round($product['total'] * 100), 'Tax' => 'none' // или 'vat20', 'vat10' ]; } return [ 'Email' => $order_info['email'], 'Taxation' => 'usn_income', // СНО 'Items' => $items ]; } }
| Параметр | ЮKassa | Робокасса | T-Pay |
|---|---|---|---|
| Комиссия (карты) | от 2.8% | от 2.3% | от 2.49% |
| СБП | 0% | 0.4% | 0.4% |
| Вывод средств | 1-2 дня | 1-3 дня | 1 день |
| Фискализация | ✓ | ✓ | ✓ |
| Рекурренты | ✓ | ✓ | ✓ |
| Модуль OpenCart | Официальный | Официальный | Неофициальный |
| Самозанятые | ✗ | ✓ | ✗ |
Модули доставки
СДЭК, Яндекс Доставка, Почта России
СДЭК
Курьерская доставка
- Расчёт стоимости по API
- Выбор ПВЗ на карте
- Курьерская доставка
- Постаматы
- Отслеживание
Яндекс Доставка
Экспресс и стандарт
- Экспресс (от 15 мин)
- Доставка в тот же день
- Интеграция с Яндекс.Картами
- Отслеживание курьера
Почта России
По всей России
- Доставка в любую точку РФ
- Наложенный платёж
- API расчёта тарифов
- Печать бланков
🔧 Настройка СДЭК
Зарегистрируйтесь в личном кабинете СДЭК и получите:
- Account (идентификатор клиента)
- Secure password (секретный ключ)
Расширения → Доставка → СДЭК Account: your_account_id Secure password: your_secure_password Тестовый режим: Нет (для боевого) --- Адрес отправки --- Город отправления: Москва Код города: 44 (СДЭК код) Индекс: 101000 Адрес склада: ул. Примерная, д. 1 --- Тарифы --- Склад-Склад (ПВЗ): Включено (тариф 136) Склад-Дверь: Включено (тариф 137) Дверь-Дверь: Включено (тариф 139) --- Параметры по умолчанию --- Вес по умолчанию: 0.5 кг Габариты: 20x15x10 см Наценка: 0% или фикс. сумма
<?php // catalog/model/extension/shipping/cdek.php namespace Opencart\Catalog\Model\Extension\Shipping; class Cdek extends \Opencart\System\Engine\Model { private $api_url = 'https://api.cdek.ru/v2/'; private $token; public function getQuote($address): array { $this->authenticate(); $method_data = []; if (!$this->token) { return $method_data; } // Параметры расчёта $params = [ 'from_location' => [ 'code' => $this->config->get('shipping_cdek_city_code') ], 'to_location' => [ 'postal_code' => $address['postcode'] ], 'packages' => [ [ 'weight' => $this->getCartWeight(), 'length' => 20, 'width' => 15, 'height' => 10 ] ] ]; // Тарифы для расчёта $tariffs = [ 136 => 'СДЭК ПВЗ', // Склад-Склад 137 => 'СДЭК Курьер', // Склад-Дверь 234 => 'СДЭК Постамат' // Склад-Постамат ]; foreach ($tariffs as $tariff_code => $tariff_name) { $params['tariff_code'] = $tariff_code; $result = $this->apiRequest('calculator/tariff', $params); if (isset($result['total_sum'])) { $quote_data['cdek_' . $tariff_code] = [ 'code' => 'cdek.cdek_' . $tariff_code, 'name' => $tariff_name . ' (' . $result['period_min'] . '-' . $result['period_max'] . ' дней)', 'cost' => $result['total_sum'], 'tax_class_id' => 0 ]; } } if (!empty($quote_data)) { $method_data = [ 'code' => 'cdek', 'name' => 'СДЭК', 'quote' => $quote_data, 'sort_order' => $this->config->get('shipping_cdek_sort_order'), 'error' => false ]; } return $method_data; } private function authenticate(): void { $auth_data = [ 'grant_type' => 'client_credentials', 'client_id' => $this->config->get('shipping_cdek_account'), 'client_secret' => $this->config->get('shipping_cdek_password') ]; $ch = curl_init($this->api_url . 'oauth/token'); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($auth_data)); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = json_decode(curl_exec($ch), true); curl_close($ch); $this->token = $response['access_token'] ?? null; } private function apiRequest($endpoint, $data): array { $ch = curl_init($this->api_url . $endpoint); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data)); curl_setopt($ch, CURLOPT_HTTPHEADER, [ 'Content-Type: application/json', 'Authorization: Bearer ' . $this->token ]); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = json_decode(curl_exec($ch), true); curl_close($ch); return $response ?? []; } }
🔧 Настройка Почты России
<?php // Расчёт стоимости через API Почты России class RussianPostCalculator { private $api_url = 'https://otpravka-api.pochta.ru/1.0/'; private $token; private $login; private $password; public function __construct($login, $password, $token) { $this->login = $login; $this->password = $password; $this->token = $token; } public function calculate($params): array { // Типы отправлений $mail_types = [ 'POSTAL_PARCEL' => 'Посылка', 'ONLINE_PARCEL' => 'Посылка онлайн', 'EMS' => 'EMS', 'PARCEL_CLASS_1' => 'Посылка 1 класса' ]; $results = []; foreach ($mail_types as $type => $name) { $request = [ 'index-from' => $params['from_postcode'], 'index-to' => $params['to_postcode'], 'mail-category' => 'ORDINARY', 'mail-type' => $type, 'mass' => $params['weight'], // в граммах 'dimension-type' => 'S', 'fragile' => false ]; if (isset($params['declared_value'])) { $request['declared-value'] = $params['declared_value'] * 100; } $response = $this->apiRequest('tariff', $request); if (isset($response['total-rate'])) { $results[$type] = [ 'name' => $name, 'cost' $response['total-rate'] / 100, 'delivery_days' => $response['delivery-time']['max-days'] ?? 14 ]; } } return $results; } private function apiRequest($endpoint, $data): array { $ch = curl_init($this->api_url . $endpoint); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data)); curl_setopt($ch, CURLOPT_HTTPHEADER, [ 'Content-Type: application/json', 'Authorization: AccessToken ' . $this->token, 'X-User-Authorization: Basic ' . base64_encode($this->login . ':' . $this->password) ]); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = json_decode(curl_exec($ch), true); curl_close($ch); return $response ?? []; } }
Сравнение служб доставки
| Параметр | СДЭК | Яндекс Доставка | Почта России |
|---|---|---|---|
| Сроки (Москва) | 1-2 дня | от 15 мин | 3-5 дней |
| Сроки (регионы) | 2-7 дней | 1-3 дня | 5-14 дней |
| Стоимость (1 кг, МСК) | от 250₽ | от 200₽ | от 150₽ |
| ПВЗ | 4500+ | Партнёры | 42000+ |
| Наложенный платёж | ✓ | ✗ | ✓ |
| API | REST API v2 | REST API | REST API |
| Модуль OpenCart | Есть | Нужен кастом | Есть |
Интеграция АТОЛ Онлайн
Онлайн-касса и фискализация чеков по 54-ФЗ
Все интернет-магазины обязаны отправлять электронные чеки покупателям. АТОЛ Онлайн — облачное решение, не требующее физической кассы.
АТОЛ Онлайн
Облачная касса
- Облачная фискализация
- Не нужна физическая касса
- Автоматическая отправка в ФНС
- Email/SMS чеки покупателям
- Интеграция с платёжками
Тарифы АТОЛ
Стоимость услуг
- Подключение: от 3 000₽
- Абонплата: от 3 000₽/мес
- За чек: ~2₽ (при большом объёме)
- ОФД: включено
🔧 Настройка АТОЛ Онлайн
Зарегистрируйтесь на online.atol.ru и получите:
- Login — логин интегратора
- Password — пароль
- Group code — код группы касс
- ИНН организации
Настройки кассы в личном кабинете АТОЛ: Название компании: ООО "Ваша компания" или ИП Иванов И.И. ИНН: 1234567890 Адрес расчётов: https://yoursite.ru Система налогообложения: - osn // Общая - usn_income // УСН Доходы - usn_income_outcome // УСН Доходы-Расходы - patent // Патент Email отправителя: kassa@yoursite.ru
Установите модуль АТОЛ через админку или вручную.
<?php // system/library/atol.php namespace Opencart\System\Library; class Atol { private $api_url = 'https://online.atol.ru/possystem/v4/'; private $login; private $password; private $group_code; private $inn; private $token; private $payment_address; private $sno; // Система налогообложения public function __construct($config) { $this->login = $config['login']; $this->password = $config['password']; $this->group_code = $config['group_code']; $this->inn = $config['inn']; $this->payment_address = $config['payment_address']; $this->sno = $config['sno'] ?? 'usn_income'; } /** * Получение токена авторизации */ public function getToken(): ?string { $data = [ 'login' => $this->login, 'pass' => $this->password ]; $response = $this->request('getToken', $data, false); if (isset($response['token'])) { $this->token = $response['token']; return $this->token; } return null; } /** * Отправка чека прихода (продажа) */ public function sendSellReceipt($order, $items): array { return $this->sendReceipt('sell', $order, $items); } /** * Отправка чека возврата */ public function sendRefundReceipt($order, $items): array { return $this->sendReceipt('sell_refund', $order, $items); } /** * Формирование и отправка чека */ private function sendReceipt($operation, $order, $items): array { if (!$this->token) { $this->getToken(); } // Формируем позиции чека $receipt_items = []; $total = 0; foreach ($items as $item) { $item_total = round($item['price'] * $item['quantity'], 2); $total += $item_total; $receipt_items[] = [ 'name' => mb_substr($item['name'], 0, 128), 'price' => $item['price'], 'quantity' => $item['quantity'], 'sum' => $item_total, 'measurement_unit' => 'шт', 'payment_method' => 'full_payment', // Полная оплата 'payment_object' => 'commodity', // Товар 'vat' => [ 'type' => $this->getVatType($item['tax_rate'] ?? 0) ] ]; // Если есть код маркировки if (!empty($item['marking_code'])) { $receipt_items[count($receipt_items) - 1]['nomenclature_code'] = [ 'type' => 'UNKNOWN', 'value' => $item['marking_code'] ]; } } // Добавляем доставку, если есть if (!empty($order['shipping_cost']) && $order['shipping_cost'] > 0) { $receipt_items[] = [ 'name' => 'Доставка', 'price' => $order['shipping_cost'], 'quantity' => 1, 'sum' => $order['shipping_cost'], 'payment_method' => 'full_payment', 'payment_object' => 'service', 'vat' => ['type' => 'none'] ]; $total += $order['shipping_cost']; } // Формируем чек $receipt = [ 'external_id' => $order['order_id'] . '_' . time(), 'receipt' => [ 'client' => [ 'email' => $order['email'] ], 'company' => [ 'email' => $this->payment_address, 'sno' => $this->sno, 'inn' => $this->inn, 'payment_address' => $this->payment_address ], 'items' => $receipt_items, 'payments' => [ [ 'type' => 1, // Электронная оплата 'sum' => $total ] ], 'total' => $total ], 'timestamp' => date('d.m.Y H:i:s') ]; // Добавляем телефон если есть if (!empty($order['telephone'])) { $receipt['receipt']['client']['phone'] = $this->formatPhone($order['telephone']); } // Отправляем чек $endpoint = $this->group_code . '/' . $operation; return $this->request($endpoint, $receipt); } /** * Проверка статуса чека */ public function checkStatus($uuid): array { if (!$this->token) { $this->getToken(); } $endpoint = $this->group_code . '/report/' . $uuid; return $this->request($endpoint, [], true, 'GET'); } /** * Определение типа НДС */ private function getVatType($rate): string { return match(intval($rate)) { 20 => 'vat20', 10 => 'vat10', 0 => 'vat0', default => 'none' }; } /** * Форматирование телефона */ private function formatPhone($phone): string { $phone = preg_replace('/[^0-9]/', '', $phone); if (strlen($phone) == 10) { $phone = '7' . $phone; } return '+' . $phone; } /** * HTTP запрос к API */ private function request($endpoint, $data, $auth = true, $method = 'POST'): array { $ch = curl_init($this->api_url . $endpoint); $headers = ['Content-Type: application/json; charset=utf-8']; if ($auth && $this->token) { $headers[] = 'Token: ' . $this->token; } curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_TIMEOUT, 30); if ($method === 'POST') { curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data)); } $response = curl_exec($ch); $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); $result = json_decode($response, true) ?? []; $result['http_code'] = $http_code; return $result; } }
Автоматическая отправка чеков
<?php // catalog/controller/extension/module/atol_fiscalization.php namespace Opencart\Catalog\Controller\Extension\Module; class AtolFiscalization extends \Opencart\System\Engine\Controller { /** * Событие после изменения статуса заказа */ public function onOrderStatusChange(&$route, &$args): void { $order_id = $args[0]; $new_status_id = $args[1]; // Статус "Оплачен" — отправляем чек продажи $paid_status_id = $this->config->get('module_atol_paid_status_id'); if ($new_status_id == $paid_status_id) { $this->sendSellReceipt($order_id); } // Статус "Возврат" — отправляем чек возврата $refund_status_id = $this->config->get('module_atol_refund_status_id'); if ($new_status_id == $refund_status_id) { $this->sendRefundReceipt($order_id); } } private function sendSellReceipt($order_id): void { $this->load->model('checkout/order'); $order_info = $this->model_checkout_order->getOrder($order_id); if (!$order_info) { return; } // Проверяем, не отправлен ли уже чек $this->load->model('extension/module/atol'); if ($this->model_extension_module_atol->isReceiptSent($order_id, 'sell')) { return; } // Получаем товары заказа $order_products = $this->model_checkout_order->getProducts($order_id); $items = []; foreach ($order_products as $product) { $items[] = [ 'name' => $product['name'], 'price' => $product['price'], 'quantity' => $product['quantity'], 'tax_rate' => $product['tax'] ?? 0, 'marking_code' => $this->getMarkingCode($product['product_id'], $order_id) ]; } // Инициализируем АТОЛ $atol = new \Opencart\System\Library\Atol([ 'login' => $this->config->get('module_atol_login'), 'password' => $this->config->get('module_atol_password'), 'group_code' => $this->config->get('module_atol_group_code'), 'inn' => $this->config->get('module_atol_inn'), 'payment_address' => $this->config->get('config_url'), 'sno' => $this->config->get('module_atol_sno') ]); $order_data = [ 'order_id' => $order_id, 'email' => $order_info['email'], 'telephone' => $order_info['telephone'], 'shipping_cost' => $this->getShippingCost($order_id) ]; $result = $atol->sendSellReceipt($order_data, $items); // Сохраняем результат $this->model_extension_module_atol->saveReceipt($order_id, 'sell', $result); // Логируем $this->log->write('ATOL: Чек продажи для заказа #' . $order_id . ' - ' . json_encode($result)); } }
Зарегистрируйте обработчик в admin/controller/extension/module/atol.php:
// При установке модуля регистрируем событие $this->load->model('setting/event'); $this->model_setting_event->addEvent([ 'code' => 'atol_fiscalization', 'description' => 'Отправка чеков в АТОЛ', 'trigger' => 'catalog/model/checkout/order/addHistory/after', 'action' => 'extension/module/atol_fiscalization|onOrderStatusChange', 'status' => 1, 'sort_order' => 0 ]);
Интеграция с Честным знаком
Работа с маркированными товарами через API
С 2024 года обязательна маркировка для: обуви, одежды, парфюмерии, шин, фототоваров, молочной продукции, воды, пива и других категорий. Штрафы за нарушение — до 300 000₽.
Что такое Честный знак
Система маркировки
- Государственная система маркировки
- Data Matrix код на каждом товаре
- Отслеживание от производителя до покупателя
- Передача кодов при продаже
Что нужно сделать
Для интернет-магазина
- Регистрация в ГИС МТ
- Получение УКЭП (электронная подпись)
- Сканирование кодов при приёмке
- Передача кодов в чеке при продаже
Маркируемые товары
| Категория | Код товарной группы | Обязательна с |
|---|---|---|
| Обувь | shoes | 01.07.2020 |
| Одежда (лёгкая промышленность) | lp | 01.01.2021 |
| Парфюмерия | perfumery | 01.10.2020 |
| Шины | tires | 01.11.2020 |
| Фототовары | photo | 01.10.2020 |
| Молочная продукция | milk | 01.09.2022 |
| Вода | water | 01.03.2023 |
| Пиво | beer | 01.04.2024 |
| БАДы | supplements | 01.10.2023 |
🔧 Интеграция с API Честного знака
<?php // system/library/chestny_znak.php namespace Opencart\System\Library; class ChestnyZnak { // Боевой URL private $api_url = 'https://markirovka.crpt.ru/api/v3/'; // Тестовый URL private $test_api_url = 'https://markirovka.sandbox.crpt.tech/api/v3/'; private $token; private $client_id; private $client_secret; private $test_mode; public function __construct($config) { $this->client_id = $config['client_id']; $this->client_secret = $config['client_secret']; $this->test_mode = $config['test_mode'] ?? false; } /** * Получение URL API */ private function getApiUrl(): string { return $this->test_mode ? $this->test_api_url : $this->api_url; } /** * Авторизация по сертификату (УКЭП) */ public function authenticate(): bool { // Шаг 1: Получаем случайные данные для подписи $auth_data = $this->request('auth/cert/key', [], 'GET'); if (!isset($auth_data['uuid'], $auth_data['data'])) { return false; } // Шаг 2: Подписываем данные УКЭП (требуется CryptoPro) $signature = $this->signData($auth_data['data']); // Шаг 3: Отправляем подпись и получаем токен $token_response = $this->request('auth/cert/' . $auth_data['uuid'], [ 'data' => $signature ]); if (isset($token_response['token'])) { $this->token = $token_response['token']; return true; } return false; } /** * Проверка кода маркировки */ public function checkCode($code, $product_group = 'lp'): array { $this->ensureAuthenticated(); $endpoint = 'cis/info'; $response = $this->request($endpoint, [ 'cis' => $code, 'productGroup' => $product_group ]); return $response; } /** * Получение информации о нескольких кодах */ public function checkCodes(array $codes, $product_group = 'lp'): array { $this->ensureAuthenticated(); $results = []; // API позволяет проверять до 100 кодов за раз $chunks = array_chunk($codes, 100); foreach ($chunks as $chunk) { $response = $this->request('cis/info/array', [ 'cisList' => $chunk, 'productGroup' => $product_group ]); if (isset($response['cisInfos'])) { $results = array_merge($results, $response['cisInfos']); } } return $results; } /** * Вывод товара из оборота (при продаже) * Выполняется автоматически через ККТ при передаче кода в чек */ public function withdrawFromCirculation(array $codes, $product_group = 'lp'): array { $this->ensureAuthenticated(); $document = [ 'product_group' => $product_group, 'withdrawal_type' => 'RETAIL', // Розничная продажа 'cis_list' => $codes ]; return $this->request('lk/documents/withdrawal', $document); } /** * Возврат товара в оборот */ public function returnToCirculation(array $codes, $product_group = 'lp'): array { $this->ensureAuthenticated(); $document = [ 'product_group' => $product_group, 'return_type' => 'RETAIL_RETURN', 'cis_list' => $codes ]; return $this->request('lk/documents/return', $document); } /** * Приёмка товара (от поставщика) */ public function acceptGoods($document_id): array { $this->ensureAuthenticated(); return $this->request('lk/receipt/accept', [ 'document_id' => $document_id ]); } /** * Получение входящих документов (УПД от поставщиков) */ public function getIncomingDocuments($date_from = null): array { $this->ensureAuthenticated(); $params = [ 'direction' => 'INCOMING', 'limit' => 100 ]; if ($date_from) { $params['dateFrom'] = $date_from; } return $this->request('lk/documents', $params, 'GET'); } /** * Проверка авторизации */ private function ensureAuthenticated(): void { if (!$this->token) { $this->authenticate(); } } /** * Подпись данных УКЭП (заглушка - требуется CryptoPro) */ private function signData($data): string { // Здесь должна быть интеграция с CryptoPro CSP // Варианты: // 1. CryptoPro PHP extension // 2. Внешний сервис подписи // 3. КриптоАРМ ГОСТ // Пример вызова через командную строку: // $signed = shell_exec("cryptcp -sign -der -cert $cert_thumbprint $data"); throw new \Exception('Требуется настройка CryptoPro для подписи'); } /** * HTTP запрос к API */ private function request($endpoint, $data = [], $method = 'POST'): array { $url = $this->getApiUrl() . $endpoint; if ($method === 'GET' && !empty($data)) { $url .= '?' . http_build_query($data); } $ch = curl_init($url); $headers = [ 'Content-Type: application/json', 'Accept: application/json' ]; if ($this->token) { $headers[] = 'Authorization: Bearer ' . $this->token; } curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_TIMEOUT, 60); if ($method === 'POST') { curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data)); } $response = curl_exec($ch); $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); $result = json_decode($response, true) ?? []; $result['_http_code'] = $http_code; return $result; } }
Управление кодами маркировки в OpenCart
<?php // admin/model/extension/module/marking.php namespace Opencart\Admin\Model\Extension\Module; class Marking extends \Opencart\System\Engine\Model { /** * Добавление кода маркировки к товару */ public function addMarkingCode($product_id, $marking_code): int { $this->db->query(" INSERT INTO `" . DB_PREFIX . "product_marking` SET product_id = '" . (int)$product_id . "', marking_code = '" . $this->db->escape($marking_code) . "', status = 'available', date_added = NOW() "); return $this->db->getLastId(); } /** * Массовый импорт кодов маркировки */ public function importMarkingCodes($product_id, array $codes): int { $imported = 0; foreach ($codes as $code) { $code = trim($code); if (empty($code)) { continue; } // Проверяем, нет ли уже такого кода $existing = $this->db->query(" SELECT marking_id FROM `" . DB_PREFIX . "product_marking` WHERE marking_code = '" . $this->db->escape($code) . "' "); if (!$existing->num_rows) { $this->addMarkingCode($product_id, $code); $imported++; } } return $imported; } /** * Получение доступного кода для товара */ public function getAvailableCode($product_id): ?array { $query = $this->db->query(" SELECT * FROM `" . DB_PREFIX . "product_marking` WHERE product_id = '" . (int)$product_id . "' AND status = 'available' ORDER BY date_added ASC LIMIT 1 "); return $query->num_rows ? $query->row : null; } /** * Резервирование кода для заказа */ public function reserveCode($marking_id, $order_id): bool { $this->db->query(" UPDATE `" . DB_PREFIX . "product_marking` SET order_id = '" . (int)$order_id . "', status = 'reserved' WHERE marking_id = '" . (int)$marking_id . "' AND status = 'available' "); return $this->db->countAffected() > 0; } /** * Подтверждение продажи (код выведен из оборота) */ public function confirmSold($marking_id): void { $this->db->query(" UPDATE `" . DB_PREFIX . "product_marking` SET status = 'sold', date_sold = NOW() WHERE marking_id = '" . (int)$marking_id . "' "); } /** * Возврат кода в оборот */ public function returnCode($marking_id): void { $this->db->query(" UPDATE `" . DB_PREFIX . "product_marking` SET status = 'returned', order_id = NULL WHERE marking_id = '" . (int)$marking_id . "' "); } /** * Получение кодов маркировки для заказа */ public function getOrderMarkingCodes($order_id): array { $query = $this->db->query(" SELECT pm.*, p.name as product_name, p.model FROM `" . DB_PREFIX . "product_marking` pm LEFT JOIN `" . DB_PREFIX . "product_description` p ON (pm.product_id = p.product_id AND p.language_id = '" . (int)$this->config->get('config_language_id') . "') WHERE pm.order_id = '" . (int)$order_id . "' "); return $query->rows; } /** * Статистика по кодам маркировки */ public function getStatistics($product_id = null): array { $where = $product_id ? "WHERE product_id = '" . (int)$product_id . "'" : ''; $query = $this->db->query(" SELECT status, COUNT(*) as count FROM `" . DB_PREFIX . "product_marking` " . $where . " GROUP BY status "); $stats = [ 'available' => 0, 'reserved' => 0, 'sold' => 0, 'returned' => 0 ]; foreach ($query->rows as $row) { $stats[$row['status']] = (int)$row['count']; } $stats['total'] = array_sum($stats); return $stats; } }
Передача кода маркировки в чек
Код маркировки передаётся в чек через поле nomenclature_code в АТОЛ или аналогичное поле в других системах. При фискализации чека код автоматически выводится из оборота в системе Честный знак.
// Формирование позиции чека с кодом маркировки $receipt_item = [ 'name' => 'Футболка мужская размер L', 'price' => 1990.00, 'quantity' => 1, 'sum' => 1990.00, 'measurement_unit' => 'шт', 'payment_method' => 'full_payment', 'payment_object' => 'commodity', 'vat' => ['type' => 'none'], // Код маркировки (Data Matrix) 'nomenclature_code' => [ 'type' => 'UNKNOWN', // или 'EAN13', 'ITF14' 'value' => '010460406000600021N4N57RSCBUZTQ' // полный код DataMatrix ], // Для товарной группы (необязательно) 'product_code' => [ 'code' => '04604060006000', // GTIN 'product_id' => 'N4N57RSCBUZTQ', // Серийный номер 'product_type' => '1' // Тип (для мехов/драгоценностей) ] ];
Оптимизация производительности
Кэширование, оптимизация БД, CDN
PHP OPcache
Кэш байткода
Ускорение PHP в 2-3 раза. Обязательно для продакшена.
Redis Cache
Кэш сессий и данных
Кэширование сессий, запросов к БД, объектов.
CDN
Статика и изображения
CloudFlare, KeyCDN для быстрой загрузки.
Настройка Redis для OpenCart
<?php // system/library/cache/redis.php namespace Opencart\System\Library\Cache; class Redis { private $redis; private $prefix = 'oc_'; private $expire = 3600; public function __construct($config = []) { $this->redis = new \Redis(); $host = $config['host'] ?? '127.0.0.1'; $port = $config['port'] ?? 6379; $this->redis->connect($host, $port); if (!empty($config['password'])) { $this->redis->auth($config['password']); } if (isset($config['database'])) { $this->redis->select($config['database']); } $this->expire = $config['expire'] ?? 3600; } public function get($key): mixed { $data = $this->redis->get($this->prefix . $key); if ($data === false) { return null; } return json_decode($data, true); } public function set($key, $value, $expire = null): void { $expire = $expire ?? $this->expire; $this->redis->setex( $this->prefix . $key, $expire, json_encode($value) ); } public function delete($key): void { $this->redis->del($this->prefix . $key); } public function flush(): void { $keys = $this->redis->keys($this->prefix . '*'); if ($keys) { $this->redis->del($keys); } } }
Оптимизация базы данных
-- Добавляем недостающие индексы для ускорения -- Индекс на товары по статусу и количеству ALTER TABLE `oc_product` ADD INDEX `idx_status_quantity` (`status`, `quantity`); -- Индекс на категории товаров ALTER TABLE `oc_product_to_category` ADD INDEX `idx_category_product` (`category_id`, `product_id`); -- Индекс на заказы по дате и статусу ALTER TABLE `oc_order` ADD INDEX `idx_date_status` (`date_added`, `order_status_id`); -- Индекс на историю заказов ALTER TABLE `oc_order_history` ADD INDEX `idx_order_date` (`order_id`, `date_added`); -- Оптимизация таблиц OPTIMIZE TABLE `oc_product`, `oc_product_description`, `oc_category`, `oc_order`, `oc_customer`, `oc_session`; -- Очистка старых сессий DELETE FROM `oc_session` WHERE expire < NOW(); -- Очистка старых логов API DELETE FROM `oc_api_session` WHERE date_added < DATE_SUB(NOW(), INTERVAL 7 DAY);
Оптимизация изображений
<?php // system/library/image.php - модификация public function save($file, $quality = 90): void { $info = pathinfo($file); $extension = strtolower($info['extension']); // Автоматическая конвертация в WebP if (function_exists('imagewebp') && in_array($extension, ['jpg', 'jpeg', 'png'])) { $webp_file = $info['dirname'] . '/' . $info['filename'] . '.webp'; if (!file_exists($webp_file)) { imagewebp($this->image, $webp_file, $quality); } } // Сохраняем оригинал switch ($extension) { case 'jpeg': case 'jpg': imagejpeg($this->image, $file, $quality); break; case 'png': imagepng($this->image, $file); break; case 'webp': imagewebp($this->image, $file, $quality); break; } }
CRON-задания для оптимизации
# Очистка кэша каждую ночь в 3:00 0 3 * * * php /var/www/html/cli/cache_clear.php # Оптимизация БД раз в неделю 0 4 * * 0 php /var/www/html/cli/db_optimize.php # Синхронизация с 1С каждые 30 минут */30 * * * * php /var/www/html/cli/sync_1c.php # Обновление курсов валют каждый день 0 9 * * * php /var/www/html/cli/currency_update.php # Отправка отложенных email */5 * * * * php /var/www/html/cli/mail_queue.php # Проверка статусов доставки 0 */2 * * * php /var/www/html/cli/delivery_status.php # Генерация sitemap 0 6 * * * php /var/www/html/cli/sitemap_generate.php
Безопасность
Защита магазина от взлома и атак
Обязательные меры
Минимум для продакшена
- SSL-сертификат (HTTPS)
- Сложный пароль админа
- Переименование /admin/
- Удаление папки /install/
- Регулярные бэкапы
- Обновления безопасности
Дополнительная защита
Продвинутые меры
- Fail2ban для SSH
- WAF (CloudFlare/ModSecurity)
- Двухфакторная авторизация
- Ограничение доступа по IP
- Мониторинг файлов
- Security headers
Переименование админки
# 1. Переименовываем папку admin mv /var/www/html/admin /var/www/html/secure_panel_xyz123 # 2. Обновляем config.php в админке nano /var/www/html/secure_panel_xyz123/config.php # Меняем строки: # define('DIR_APPLICATION', '/var/www/html/secure_panel_xyz123/'); # define('HTTP_SERVER', 'https://yoursite.ru/secure_panel_xyz123/'); # define('HTTPS_SERVER', 'https://yoursite.ru/secure_panel_xyz123/');
Защита .htaccess
# Защита от XSS Header always set X-XSS-Protection "1; mode=block" Header always set X-Content-Type-Options "nosniff" Header always set X-Frame-Options "SAMEORIGIN" Header always set Referrer-Policy "strict-origin-when-cross-origin" # Content Security Policy Header always set Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://cdn.jsdelivr.net; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com; img-src 'self' data: https:;" # Запрет доступа к служебным файлам <FilesMatch "^(config|php\.ini|\.htaccess|\.env)"> Order allow,deny Deny from all </FilesMatch> # Запрет выполнения PHP в папке изображений <Directory "/var/www/html/image"> php_admin_flag engine Off </Directory> # Защита от брутфорса (ограничение запросов) <IfModule mod_evasive20.c> DOSHashTableSize 3097 DOSPageCount 5 DOSSiteCount 100 DOSPageInterval 1 DOSSiteInterval 1 DOSBlockingPeriod 60 </IfModule>
Автоматические бэкапы
#!/bin/bash # Настройки SITE_PATH="/var/www/html" BACKUP_PATH="/var/backups/opencart" DB_NAME="opencart_db" DB_USER="opencart_user" DB_PASS="your_password" DATE=$(date +%Y%m%d_%H%M%S) DAYS_KEEP=7 # Создаём папку для бэкапов mkdir -p $BACKUP_PATH # Бэкап базы данных mysqldump -u$DB_USER -p$DB_PASS $DB_NAME | gzip > $BACKUP_PATH/db_$DATE.sql.gz # Бэкап файлов (только важные) tar -czf $BACKUP_PATH/files_$DATE.tar.gz \ -C $SITE_PATH \ config.php \ admin/config.php \ image/catalog \ system/storage \ --exclude="*.log" # Удаляем старые бэкапы find $BACKUP_PATH -type f -mtime +$DAYS_KEEP -delete # Опционально: отправка на удалённый сервер # rsync -avz $BACKUP_PATH/ user@backup-server:/backups/opencart/ echo "Бэкап завершён: $DATE"
Всегда обновляйте OpenCart! Регулярно проверяйте обновления на GitHub.
Распространённые проблемы:
• SQL-инъекции в устаревших модулях
• XSS в пользовательских данных
• Загрузка вредоносных файлов через формы
• Утечка данных через /system/storage/
Итоговый чек-лист запуска
Проверьте всё перед запуском магазина
🔧 Техническая часть
- PHP 8.1+ установлен
- SSL сертификат настроен
- OpenCart установлен
- Папка /install/ удалена
- Админка переименована
- Права на файлы настроены
- OPcache включен
- Бэкапы настроены
💳 Оплата
- ЮKassa/Робокасса подключена
- Тестовый платёж прошёл
- Callback URL настроен
- Боевой режим включен
- Возвраты работают
📦 Доставка
- СДЭК/ПР подключены
- Расчёт стоимости работает
- Адрес склада указан
- Тарифы выбраны
- Создание заявок работает
🧾 Фискализация
- АТОЛ Онлайн подключен
- Тестовый чек отправлен
- СНО указана верно
- Email/SMS чеки приходят
- Возвратные чеки работают
✅ Маркировка (если нужна)
- Регистрация в ГИС МТ
- УКЭП получена
- API подключен
- Коды загружены в систему
- Передача в чек настроена
📋 Юридическое
- Политика конфиденциальности
- Пользовательское соглашение
- Договор оферты
- Реквизиты компании на сайте
- Согласие на обработку ПД