После подтверждения платежа покупатель ожидает мгновенный доступ к файлу. Если ссылка истекла, вебхук не обработан или файл лежит в public-директории — скачивание срывается. По нашим данным, до 30% сбоев при цифровых продажах связаны именно с некорректной обработкой вебхуков. Мы устраняем эти риски, внедряя верификацию подписей и асинхронную генерацию ссылок. Каждая минута простоя системы скачивания оборачивается потерей клиентов и репутации. Закажите реализацию надёжного механизма скачивания для вашего проекта.
Как обработать вебхук платёжной системы надёжно?
Ключевой момент — верификация подписи. Без неё злоумышленник может сгенерировать поддельный вебхук и получить цифровой товар бесплатно. Используем Factory для выбора обработчика под каждый провайдер: Stripe, PayPal, Robokassa. После проверки подписи и парсинга результата обновляем заказ в транзакции и генерируем событие.
class PaymentWebhookController { public function handle(Request $request, string $provider): JsonResponse { $handler = PaymentHandlerFactory::make($provider); // Верифицируем подпись вебхука if (!$handler->verifySignature($request)) { Log::warning('Invalid payment webhook signature', ['provider' => $provider]); abort(400); } $paymentResult = $handler->parse($request); if ($paymentResult->isSuccessful()) { $order = Order::where('payment_id', $paymentResult->transactionId)->firstOrFail(); DB::transaction(function () use ($order, $paymentResult) { $order->update([ 'status' => 'paid', 'paid_at' => now(), 'payment_id' => $paymentResult->transactionId, ]); event(new PaymentConfirmedEvent($order)); }); } return response()->json(['ok' => true]); } } Как выбрать между синхронным и асинхронным созданием ссылок?
Синхронное выполнение (inline в Listener) — покупатель получает email через 1–2 секунды после оплаты. Подходит для малого числа позиций и низкой нагрузки. Асинхронное (через Queue) — надёжнее при высокой нагрузке, так как не задерживает HTTP-ответ вебхуку. Ниже сравнение:
| Способ | Задержка email | Нагрузка на ответ вебхука | Подходит для |
|---|---|---|---|
| Синхронно | 1–2 с | Высокая | Мало заказов, низкий трафик |
| Асинхронно (Redis) | 5–30 с | Минимальная | Высокая нагрузка, большие объёмы |
Асинхронный подход с использованием Laravel Horizon позволяет мониторить очереди и автоматически повторять неудачные попытки. Время обработки вебхука в среднем 150 мс.
class CreateDownloadLinksListener implements ShouldQueue { public $queue = 'digital-downloads'; public $tries = 5; public $backoff = [5, 15, 30, 60, 120]; public function handle(PaymentConfirmedEvent $event): void { $order = $event->order; $digitalItems = $order->items->filter( fn($item) => $item->product->digitalProduct !== null ); foreach ($digitalItems as $item) { app(CreateDigitalDownloadAction::class)->execute($item); } } } Как защитить ссылки скачивания?
Токен генерируется как UUID v4, его хеш SHA-256 хранится в БД. Ссылка может быть одноразовой (downloads_limit = 1) или с ограничением по времени. При каждом скачивании проверяется срок действия, лимит и статус заказа. Это предотвращает утечку, даже если ссылка перехвачена.
Как отдавать большие файлы без нагрузки на сервер?
PHP-стриминг через Storage::download() загружает файл в буфер, что нагружает память при размерах >500 МБ. Для крупных файлов используем X-Accel-Redirect или presigned URL S3. PHP только авторизует, а файл отдаёт сервер или CDN. X-Accel-Redirect снижает нагрузку на PHP до 0,001% по сравнению с прямым стримингом. Настройка включает следующие шаги:
- Разместить файлы вне
public(например,/var/private-files/). - Настроить nginx
internallocation для обслуживания защищённых файлов. - В PHP эндпоинте валидировать токен и возвращать заголовок
X-Accel-Redirect.
| Метод | Скорость | Нагрузка на сервер | Подходит для файлов |
|---|---|---|---|
| PHP stream (Storage::download) | Средняя | Высокая | <500 МБ |
| X-Accel-Redirect | Высокая | Минимальная | >500 МБ |
| S3 Presigned URL | Максимальная | Нулевая | Любые |
public function downloadViaAccel(DigitalOrderDownload $download): Response { $this->validateDownload($download); $this->recordDownload($download); $internalPath = '/private-files/' . $download->digitalProduct->storage_path; return response('', 200, [ 'X-Accel-Redirect' => $internalPath, 'Content-Type' => $download->digitalProduct->mime_type, 'Content-Disposition' => 'attachment; filename="' . $download->digitalProduct->original_filename . '"', 'X-Content-Type-Options' => 'nosniff', ]); } Email с ссылкой на скачивание
Покупатель получает письмо с уникальной ссылкой, сроком действия и количеством доступных скачиваний. Реализована возможность повторной отправки с ограничением — не чаще раза в 5 минут.
class DigitalDownloadReadyMail extends Mailable { use Queueable, SerializesModels; public function __construct( private readonly DigitalOrderDownload $download, ) {} public function build(): self { $downloadUrl = route('digital.download', $this->download->token); return $this ->subject('Ваша покупка готова к скачиванию') ->markdown('emails.digital-download-ready', [ 'downloadUrl' => $downloadUrl, 'productName' => $this->download->digitalProduct->product->name, 'expiresAt' => $this->download->expires_at?->format('d.m.Y'), 'downloadsLimit' => $this->download->downloads_limit, ]); } } Типичные ошибки при реализации
Ошибка №1: пропуск верификации подписи вебхука. Решение: всегда проверять подпись через провайдерский SDK. Ошибка №2: синхронное создание ссылок при высокой нагрузке — приводит к тайм-аутам вебхуков. Решение: использовать очереди с ретраями. Ошибка №3: хранение файлов в public-директории. Решение: размещать файлы за пределами document root и отдавать через контроллер с авторизацией.
Процесс работы и что входит
- Аналитика: проектирование схемы данных
digital_order_downloads, хеши токенов, индексы. - Интеграция с платёжной системой: обработка вебхуков, валидация подписей, обработка ошибок.
- Генерация и защита ссылок: UUID + хеш, лимиты по времени и числу скачиваний.
- Выбор механизма отдачи: PHP-стриминг, X-Accel-Redirect или S3 presigned URL.
- Email-уведомления с возможностью повторной отправки и rate limiting.
- Мониторинг и логирование: отслеживание успешных и неудачных загрузок.
- Документация: API, настройка nginx, инструкция по деплою.
Почему стоит доверять реализацию профессионалам?
Многолетний опыт реализации подобных систем для 15+ проектов — от небольших интернет-магазинов до образовательных платформ с тысячами загрузок в день. Мы избегаем типичных ошибок: неверная валидация вебхуков, утечка памяти при стриминге, необратимые истечения ссылок. Архитектура закладывает масштабирование с первой строки кода. Стоимость внедрения рассчитывается индивидуально в зависимости от сложности интеграции и необходимого функционала. Свяжитесь с нами для получения консультации и точной оценки.







