Экспорт данных из веб-приложения: реализация под ключ

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

Разработка и обслуживание любых видов сайтов:

Информационные сайты или веб-приложения
Сайты визитки, landing page, корпоративные сайты, онлайн каталоги, квиз, промо-сайты, блоги, новостные ресурсы, информационные порталы, форумы, агрегаторы
Сайты или веб-приложения электронной коммерции
Интернет-магазины, B2B-порталы, маркетплейсы, онлайн-обменники, кэшбэк-сайты, биржи, дропшиппинг-платформы, парсеры товаров
Веб-приложения для управления бизнес-процессами
CRM-системы, ERP-системы, корпоративные порталы, системы управления производством, парсеры информации
Сайты или веб-приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, конструкторы сайтов, порталы предоставления электронных услуг, видеохостинги, тематические порталы

Это лишь некоторые из технических типов сайтов, с которыми мы работаем, и каждый из них может иметь свои специфические особенности и функциональность, а также быть адаптированным под конкретные потребности и цели клиента

Услуги, которые мы предлагаем
Показано 1 из 1Все 2062 услуг
Экспорт данных из веб-приложения: реализация под ключ
Средний
~3-5 дней
Часто задаваемые вопросы

Экспорт данных из веб-приложения: реализация под ключ

Согласно Статье 20 GDPR, каждый субъект данных имеет право получить свои персональные данные в структурированном, общеиспользуемом и машиночитаемом формате. Но на практике выгрузка данных на 500 000 строк часто заваливает сервер: тайм-аут 30 секунд и 502 Bad Gateway. Причина — синхронная архитектура и лимиты PHP. Мы решаем эту проблему на уровне инфраструктуры: асинхронная генерация через очереди, потоковая запись в S3 и временные signed URLs. Требования GDPR (ст. 20) обязывают предоставить персональные данные пользователя в машиночитаемом формате — мы реализуем экспорт под ключ. Свяжитесь с нами для оценки вашего проекта.

Проблемы, которые решаем

  • N+1 запросы при выгрузке данных: при выгрузке заказов с позициями каждый запрос к БД плодит новые — для 10 000 заказов это 10 001 запрос. Используем lazy loading через lazy(200) и жадную загрузку отношений.
  • Тайм-ауты и падение памяти при синхронной выгрузке >100 000 строк: PHP-скрипт упирается в memory_limit и max_execution_time. Решение — асинхронная обработка через очереди с таймаутом 600 сек.
  • Гидратация несоответствия при SSR (hydration mismatch): если данные экспорта встраиваются на фронт, React/Nuxt могут рассинхронизироваться. Экспортируем всё через API с уникальными ID.

Почему асинхронный экспорт лучше для больших данных?

Синхронный подход подходит только для малых объёмов (<10k строк). При росте данных он ведёт к блокировке интерфейса и сбросу соединения. Асинхронная схема с очередью и уведомлениями снимает нагрузку с HTTP-воркера и масштабируется горизонтально. Когда один клиент генерирует отчёт на 200k строк, другие продолжают работать без задержек.

Типичный пример: один клиент попросил выгрузку 150 000 заказов в Excel. Изначально разработчик написал синхронный скрипт — на 40-й секунде PHP упал по memory_limit. После перехода на очередь генерация заняла 2 минуты, пользователь получил письмо со ссылкой без блокировок.

Критерий Синхронный экспорт Асинхронный экспорт
Макс. объём до 10 000 строк без ограничений
Блокировка воркера да нет
Тайм-аут 30-60 сек 600+ сек
Уведомление пользователя нет (ожидание) email / websocket
Работа с S3 нет да (потоковая загрузка)
[User request] → [Create ExportJob record] → [Queue Worker]
↓
[Generate files]
↓
[Upload to S3 (zip)]
↓
[Email with download link] (signed URL, 7 days TTL)

Как мы это делаем: Laravel-реализация

Для серверной части используем Laravel с PHP 8.3+. Ключевой паттерн — сервис DataExportService, который ставит задачу в очередь. Воркер ExportUserDataJob генерирует файлы профиля (JSON), заказов (CSV с BOM), сообщений (JSON) и упаковывает их в ZIP с последующей загрузкой в S3.

class DataExportService {
    public function exportUserData(User $user): Export {
        $export = Export::create([
            'user_id' => $user->id,
            'status' => 'pending',
            'expires_at' => now()->addDays(7),
        ]);

        ExportUserDataJob::dispatch($user, $export);

        return $export;
    }
}

class ExportUserDataJob implements ShouldQueue {
    public int $timeout = 600;

    public function __construct(private User $user, private Export $export) {}

    public function handle(): void {
        $this->export->update(['status' => 'processing']);

        $tempDir = sys_get_temp_dir() . '/export_' . $this->export->id;
        mkdir($tempDir, 0777, true);

        try {
            // Профиль
            file_put_contents(
                "$tempDir/profile.json",
                json_encode($this->exportProfile(), JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT)
            );

            // Заказы
            $this->exportOrders("$tempDir/orders.csv");

            // Сообщения
            $this->exportMessages("$tempDir/messages.json");

            // Создать ZIP
            $zipPath = sys_get_temp_dir() . "/export_{$this->export->id}.zip";
            $zip = new ZipArchive();
            $zip->open($zipPath, ZipArchive::CREATE);
            foreach (glob("$tempDir/*") as $file) {
                $zip->addFile($file, basename($file));
            }
            $zip->close();

            // Загрузить в S3
            $s3Key = "exports/{$this->user->id}/{$this->export->id}/data.zip";
            Storage::disk('s3')->put($s3Key, file_get_contents($zipPath));

            $this->export->update([
                'status' => 'ready',
                's3_key' => $s3Key,
            ]);

            $this->user->notify(new ExportReadyNotification($this->export));
        } finally {
            exec("rm -rf {$tempDir}");
            if (file_exists($zipPath ?? '')) unlink($zipPath);
        }
    }

    private function exportProfile(): array {
        return [
            'id' => $this->user->id,
            'name' => $this->user->name,
            'email' => $this->user->email,
            'created_at' => $this->user->created_at->toIso8601String(),
            'profile' => $this->user->profile?->toArray(),
        ];
    }

    private function exportOrders(string $path): void {
        $handle = fopen($path, 'w');
        fprintf($handle, chr(0xEF) . chr(0xBB) . chr(0xBF)); // UTF-8 BOM
        fputcsv($handle, ['Номер', 'Дата', 'Сумма', 'Статус', 'Позиции'], ';');

        $this->user->orders()->with('items')->lazy(200)->each(function (Order $order) use ($handle) {
            $items = $order->items->map(fn($i) => "{$i->name} x{$i->quantity}")->join(', ');
            fputcsv($handle, [
                $order->number,
                $order->created_at->format('d.m.Y H:i'),
                number_format($order->total, 2),
                $order->status,
                $items,
            ], ';');
        });

        fclose($handle);
    }

    private function exportMessages(string $path): void {
        $messages = $this->user->messages()
            ->select('id', 'subject', 'body', 'created_at')
            ->get()
            ->map(fn($m) => [
                'id' => $m->id,
                'subject' => $m->subject,
                'body' => strip_tags($m->body),
                'date' => $m->created_at->toIso8601String(),
            ]);

        file_put_contents($path, json_encode($messages, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT));
    }

    public function failed(\Throwable $e): void {
        $this->export->update(['status' => 'failed']);
        Log::error('Export failed', ['export_id' => $this->export->id, 'error' => $e->getMessage()]);
    }
}

Как работает signed URL для скачивания?

Чтобы не хранить архивы вечно, используем временные ссылки S3 с TTL 15 минут. Пользователь получает письмо с уникальной ссылкой, которая ведёт напрямую в S3 — минуя наш сервер.

public function download(Export $export): RedirectResponse
{
    $this->authorize('download', $export);

    if ($export->status !== 'ready' || $export->expires_at->isPast()) {
        abort(410, 'Экспорт недоступен или устарел');
    }

    $url = Storage::disk('s3')->temporaryUrl($export->s3_key, now()->addMinutes(15));

    return redirect()->away($url);
}

Как подобрать формат экспорта?

Выбор формата зависит от цели: для API и GDPR-выгрузки подходит JSON, для таблиц и Excel — CSV с BOM, для бухгалтерии — XLSX с форматированием, для B2B интеграций — XML. Если требуется архив нескольких файлов, используем ZIP.

Формат Применение Инструмент
JSON API, GDPR-выгрузка PHP json_encode, Node JSON.stringify
CSV Таблицы, Excel fputcsv, csv-writer
XLSX Бухгалтерия, аналитика PhpSpreadsheet, ExcelJS
XML B2B интеграции SimpleXML, xmlbuilder2
ZIP Архив нескольких файлов ZipArchive, archiver (Node)

Процесс работы

  1. Аналитика — изучаем структуру данных, объёмы, требования к форматам.
  2. Проектирование — выбираем стек (очередь, хранилище), проектируем схему БД для экспортов.
  3. Разработка — пишем сервис, воркеры, контроллеры, тесты.
  4. Тестирование — нагрузочное тестирование с реальными объёмами, проверка тайм-аутов.
  5. Деплой — настраиваем очереди (Redis, SQS), S3, кроны для очистки.
  6. Документация — передаём архитектурную документацию и инструкцию.

Что входит в работу

  • Архитектурная документация с описанием потоков данных.
  • Исходный код с комментариями и строгим типизированием.
  • Инструкция по деплою с примерами конфигурации очередей и S3.
  • Обучение сотрудников поддержки.
  • Гарантия 3 месяца на бесперебойную работу.

Сроки и стоимость

Базовый экспорт данных пользователя (JSON + CSV в ZIP): 2–3 дня. С очередью, S3 и email-уведомлением: 3–4 дня. GDPR-совместимый экспорт всех персональных данных: 4–5 дней. Стоимость рассчитывается индивидуально и зависит от объёмов и количества форматов: базовый вариант от $140–200, комплексный — от $400–580. Опыт нашей команды — 5+ лет и 50+ проектов по экспорту данных. Закажите экспорт для вашего проекта — обсудим задачу и вернёмся с оценкой в течение 1 дня.

Свяжитесь с нами, чтобы обсудить ваш проект и получить точную оценку.

Наши компетенции:

Последние работы

  • Разработка сайта компании B2B ADVANCE
    Разработка сайта компании B2B ADVANCE
    1542
  • Разработка веб-приложения для компании FEEDME
    Разработка веб-приложения для компании FEEDME
    1393
  • Разработка веб-сайта для компании БЕЛФИНГРУПП
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    1081
  • Разработка интернет магазина для компании FURNORO
    Разработка интернет магазина для компании FURNORO
    1368
  • Разработка веб-приложения для компании Enviok
    Разработка веб-приложения для компании Enviok
    1139
  • Разработка веб-сайта для компании ФИКСПЕР
    Разработка веб-сайта для компании ФИКСПЕР
    1060