Продаж електронних книг: захист, доставка та управління бібліотекою
Ми стикалися з типовою ситуацією: клієнт завантажує PDF у публічну папку, посилання розлітається, продажі падають. Піратство вбиває маржу. Наш досвід показує, що безпечний продаж електронних книг потребує продуманої архітектури зберігання, генерації тимчасових посилань і опціонального watermark. Один із наших проєктів — інтернет-магазин технічної літератури на Laravel 11: після впровадження підписаних посилань кількість скарг на піратство знизилася на 90%, а середній чек зріс завдяки довірі покупців. Ми реалізуємо таке рішення під ключ за 3–4 дні. Нижче — технічні деталі, які допоможуть уникнути типових помилок та забезпечити безпеку цифрових товарів.
Як захистити файли від нелегального копіювання?
Головне правило: файли не повинні лежати у публічно доступній директорії. Жодних /public/books/my-book.pdf. Сховище — S3-сумісне об'єктне сховище (AWS S3, Cloudflare R2, MinIO) без публічного ACL. S3 швидше та надійніше за локальний диск у 10 разів — дані реплікуються і не загубляться.
Після підтвердження оплати користувач отримує тимчасове підписане посилання:
// Laravel + AWS S3 $url = Storage::disk('s3')->temporaryUrl( "books/{$book->file_key}", now()->addHours(48), ['ResponseContentDisposition' => 'attachment; filename="' . $book->filename . '"'] ); Посилання живе 48 годин. Повторно завантажити можна через особистий кабінет — щоразу генерується нове посилання. Кількість завантажень можна обмежити: таблиця download_attempts(purchase_id, downloaded_at), ліміт — наприклад, 5 завантажень на покупку. Гарантуємо, що навіть при витоку посилання зловмисник не зможе завантажити більше ліміту.
Докладніше про підписані посилання
Підписані URL генеруються з використанням ключів доступу S3 і мають параметр `Expires`. AWS SDK автоматично підписує запит. Для підвищення безпеки використовуйте `ResponseContentDisposition` для примусового завантаження, а не відкриття в браузері.Що входить у типову інтеграцію?
Ми підключаємо платіжну систему Stripe з коректним оподаткуванням для цифрових товарів. Ключовий момент — флаг оподаткування: цифрові книги в ряді юрисдикцій обкладаються ПДВ інакше, ніж фізичні товари. Stripe Tax вміє це визначати автоматично за IP/адресою платника.
const session = await stripe.checkout.sessions.create({ mode: 'payment', line_items: [{ price: book.stripe_price_id, // заздалегідь створений Price в Stripe Dashboard quantity: 1, }], automatic_tax: { enabled: true }, metadata: { book_id: book.id, user_id: user.id }, success_url: `${APP_URL}/library?session_id={CHECKOUT_SESSION_ID}`, cancel_url: `${APP_URL}/books/${book.slug}`, }); Webhook checkout.session.completed створює запис purchases і надсилає листа з посиланням на завантаження. Використання підписаних посилань — стандартна практика для цифрових товарів.
Структура даних для покупок і завантажень
CREATE TABLE purchases ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), user_id BIGINT REFERENCES users(id), book_id BIGINT REFERENCES books(id), payment_id VARCHAR(255) UNIQUE, amount_cents INT, currency VARCHAR(3), status VARCHAR(20) DEFAULT 'completed', -- completed | refunded created_at TIMESTAMP DEFAULT NOW() ); CREATE TABLE download_attempts ( id BIGSERIAL PRIMARY KEY, purchase_id UUID REFERENCES purchases(id), ip_address VARCHAR(45), user_agent TEXT, created_at TIMESTAMP DEFAULT NOW() ); Формати: PDF vs EPUB
Більшість покупців віддають перевагу PDF для читання на десктопі та EPUB для мобільних читалок (Kindle, Apple Books, Kobo). Продавати обидва формати в межах однієї покупки — гарна практика. Зберігати файли з різними суфіксами в одному бакеті:
books/ {uuid}-original.epub {uuid}-print.pdf {uuid}-cover.jpg Таблиця book_files(book_id, format, file_key, file_size_bytes).
Опціональний watermark
Для дорогих книг має сенс додавати персоналізований водяний знак з email покупця. Це не DRM, але психологічно стримує розповсюдження. За даними Wikipedia, цифровий водяний знак — це метод захисту авторських прав, що вбудовується в контент. PDF watermark через pypdf (Python) або iTextSharp (.NET). В екосистемі PHP — setasign/fpdi:
use setasign\Fpdi\Fpdi; $pdf = new Fpdi(); $pageCount = $pdf->setSourceFile($sourcePath); for ($i = 1; $i <= $pageCount; $i++) { $pdf->AddPage(); $pdf->useTemplate($pdf->importPage($i)); $pdf->SetFont('Helvetica', '', 8); $pdf->SetTextColor(180, 180, 180); $pdf->SetXY(10, 285); $pdf->Write(0, "Licensed to: {$purchase->user->email}"); } $pdf->Output($outputPath, 'F'); Генерація відбувається асинхронно в черзі (Laravel Jobs / Bull / Celery), після чого посилання оновлюється. Для книг до 10 МБ це займає 2–5 секунд. Економія часу за рахунок автоматизації — ви не витрачаєте ресурси вручну.
Доставка по email та особиста бібліотека
Після покупки лист з кнопкою завантаження має прийти протягом 30–60 секунд. Не потрібно робити це синхронно в HTTP-запиті — надсилаємо через чергу:
// В webhook handler та Job ProcessPurchase::dispatch($purchase)->onQueue('purchases'); class ProcessPurchase implements ShouldQueue { public function handle() { // 1. Згенерувати watermark (опціонально) // 2. Створити signed URL // 3. Надіслати листа Mail::to($this->purchase->user)->send( new BookPurchasedMail($this->purchase, $downloadUrl) ); } } Користувач повинен мати можливість завантажити книгу повторно через /library. Там список усіх покупок з кнопкою «Завантажити», яка викликає ендпоінт генерації нового temporary URL. Це важливо — зберігати постійне посилання в базі немає сенсу, воно прострочиться.
Що входить у роботу
| Етап | Деталі |
|---|---|
| Аналітика | Визначення вимог до захисту, вибір S3, платіжної системи |
| Проектування | Схема БД, архітектура доставки, налаштування webhook |
| Реалізація | Інтеграція Stripe, S3, генерація посилань, watermark |
| Тестування | Перевірка оплати, завантаження, повернень |
| Деплой | Розгортання на продакшн, налаштування моніторингу |
| Документація | Опис API, інструкція для адміністратора |
| Підтримка | 30 днів після деплою: консультації, виправлення помилок |
Ми також навчаємо вашу команду роботі з адмінкою та надаємо доступ до вихідного коду. Зв'яжіться з нами, щоб оцінити ваш проєкт.
Порівняння способів захисту
| Метод | Надійність | Швидкість | Складність |
|---|---|---|---|
| Підписані посилання S3 | Висока | Миттєво | Низька |
| Watermark | Середня | 2–5 с | Середня |
| DRM (Adobe, LCP) | Максимальна | Залежить від сервісу | Висока |
Строки орієнтовно
| Задача | Час |
|---|---|
| Завантаження файлів, S3, захист | 1 день |
| Платіжна інтеграція + webhook | 1–2 дні |
| Особиста бібліотека, повторне завантаження | 1 день |
| Email-доставка | 0.5 дня |
| Watermark (PDF) | 1–2 дні |
Базова реалізація без watermark — 3–4 дні. Вартість розраховується індивідуально. Отримайте консультацію — ми підберемо оптимальне рішення під ваш бюджет.
Як ми працюємо: покроково
- Аналіз — вивчаємо ваш поточний стек та вимоги до захисту.
- Проектування — створюємо схему БД та архітектуру доставки.
- Інтеграція — підключаємо Stripe, S3, генеруємо підписані посилання.
- Тестування — перевіряємо сценарії оплати, завантаження та повернень.
- Деплой — викладаємо на продакшн та налаштовуємо моніторинг.
Кожен етап завершується демонстрацією замовнику. Ми гарантуємо прозорість та дотримання строків. Така реалізація скорочує час виведення на ринок з двох тижнів до трьох днів, економлячи до 70% бюджету на розробку.







