Skip to content

PHP SDK

PHP SDK verstka/sdk помогает реализовать интеграцию Verstka на PHP backend: открыть редактор, принять callback после сохранения, скачать ZIP, сохранить медиа, обновить HTML/JSON и вернуть ответ Verstka.

Перед этой страницей лучше прочитать общий flow: ОбзорИнтеграция

Установка

bash
composer require verstka/sdk

Требования:

ТребованиеЗначение
PHP8.2+
Расширенияext-json, ext-hash, ext-zip
HTTP clientGuzzle 7

Конфигурация

Обычно достаточно указать apiKey, apiSecret и публичный callbackUrl вашего сайта:

php
use Verstka\Sdk\Config\VerstkaConfig;

$config = new VerstkaConfig(
    apiKey: 'verstka-api-key',
    apiSecret: 'verstka-api-secret',
    callbackUrl: 'https://site.example/verstka/callback',
);

callbackUrl должен быть доступен Verstka backend снаружи. На этот URL Verstka придет при сохранении публикации в редакторе.

Дополнительные настройки можно задать явно:

php
$config = new VerstkaConfig(
    apiKey: 'verstka-api-key',
    apiSecret: 'verstka-api-secret',
    callbackUrl: 'https://site.example/verstka/callback',
    apiUrl: 'https://api.r2.verstka.org/integration',
    maxContentSize: 200 * 1024 * 1024,
    requestTimeout: 60.0,
    downloadTimeout: 120.0,
    debug: false,
);

apiUrl по умолчанию уже равен https://api.r2.verstka.org/integration.

1. Открыть редактор из админки

В админке лучше сделать кнопку обычной ссылкой, которая открывается в новой вкладке и ведет на route вашего backend:

html
<a
  href="/admin/verstka/edit?post=123"
  target="_blank"
>
  Редактировать в Verstka
</a>

Backend route проверяет права пользователя, загружает статью из CMS, получает editorUrl через SDK и делает redirect на этот URL. Ниже пример в стиле plain PHP; в Symfony, Laravel или другом framework верните redirect своим способом.

php
use Verstka\Sdk\Client\VerstkaClient;
use Verstka\Sdk\Config\VerstkaConfig;

function openVerstkaEditor(int $articleId, User $user, VerstkaConfig $config): void
{
    $article = ArticleRepository::find($articleId);

    if (!UserPolicy::canEdit($user, $article)) {
        throw new RuntimeException('Access denied');
    }

    $client = new VerstkaClient($config);

    $editorUrl = $client->getEditorUrl(
        materialId: (string) $article->id,
        vmsJson: $article->vms_json,
        metadata: [],
    );

    header('Location: ' . $editorUrl, true, 302);
    exit;
}

Если статья открывается впервые, vmsJson можно не передавать или передать null. Если статья уже редактировалась в Verstka, передайте последний сохраненный vmsJson, чтобы редактор открыл актуальную версию публикации.

2. Сохранить файлы через StorageAdapter

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

StorageAdapter нужно написать на стороне сайта. SDK вызывает его методы, а ваша реализация решает, куда положить файл и какой публичный URL вернуть.

Adapter получает временный файл, сохраняет его в ваше публичное хранилище uploads, CDN, S3 bucket или другое место и возвращает публичный URL.

php
use Verstka\Sdk\Storage\StorageAdapter;

final class CmsStorage implements StorageAdapter
{
    public function saveMedia(
        string $filename,
        string $tempPath,
        string $materialId,
        array $metadata,
    ): string {
        return $this->saveToCdn("articles/$materialId/$filename", $tempPath);
    }

    public function saveFontFile(
        string $filename,
        string $tempPath,
        string $materialId,
        array $metadata,
    ): string {
        return $this->saveToCdn("verstka/fonts/$filename", $tempPath);
    }

    public function saveFontsManifest(
        string $filename,
        string $tempPath,
        string $materialId,
        array $metadata,
    ): string {
        return $this->saveToCdn("verstka/fonts/$filename", $tempPath);
    }
}

Каждый метод должен вернуть URL, который будет доступен читателям сайта. SDK подставит эти URL в vmsHtml, vmsJson['assets'][*]['clientUrl'], vms_fonts.css и дерево fonts.

saveToCdn в примере - условный метод вашего приложения, который сохраняет файл и возвращает публичный URL.

Для локальной разработки можно использовать LocalStorageAdapter, но в production обычно нужен adapter под хранилище вашего сайта.

3. Принять callback после Save

Когда пользователь нажимает Save в Verstka, backend сайта получает callback. Внутри callback SDK проверяет подпись, скачивает ZIP, сохраняет медиа через StorageAdapter, заменяет временные URL файлов на публичные и вызывает ваш onFinalize.

В onFinalize нужно сохранить обновленные vmsHtml и vmsJson в базу данных сайта.

php
use Verstka\Sdk\Client\VerstkaClient;
use Verstka\Sdk\Finalize\ContentFinalizeContext;
use Verstka\Sdk\Finalize\ContentFinalizeResult;

$client = new VerstkaClient($config);
$storage = new CmsStorage();

$result = $client->processMaterialCallback(
    callbackData: $requestPayload,
    signature: $request->headers->get('X-Verstka-Signature', ''),
    storage: $storage,
    onFinalize: function (ContentFinalizeContext $ctx): ContentFinalizeResult {
        ArticleRepository::saveVerstkaContent(
            materialId: $ctx->materialId,
            vmsHtml: $ctx->vmsHtml,
            vmsJson: $ctx->vmsJson,
        );

        return new ContentFinalizeResult(success: true, vmsJson: $ctx->vmsJson);
    },
);

return json_response($result->toResponse());

ContentFinalizeContext содержит:

ПолеНазначение
materialIdID материала из CMS.
metadataMetadata из callback.
vmsJsonJSON публикации с обновленными clientUrl.
vmsHtmlHTML публикации с замененными временными URL.
savedMediaUrlsСловарь {filename: public_url}.

Важно сохранить обновленный vmsJson из callback. При следующем открытии редактора его нужно передать в getEditorUrl.

4. Обработать callback шрифтов

Если в Verstka используется свой набор шрифтов сайта, после изменения шрифтов придет отдельное событие site_fonts_updated.

Его обрабатывает processFontsCallback. Если используете один callback route для всех событий, выбирайте обработчик по $requestPayload['event'].

php
use Verstka\Sdk\Finalize\FontsFinalizeContext;
use Verstka\Sdk\Finalize\FontsFinalizeResult;

$result = $client->processFontsCallback(
    callbackData: $requestPayload,
    signature: $request->headers->get('X-Verstka-Signature', ''),
    storage: $storage,
    onFinalize: function (FontsFinalizeContext $ctx): FontsFinalizeResult {
        SiteSettings::set('verstka_fonts_css_url', $ctx->cssUrl);
        SiteSettings::set('verstka_fonts_json_url', $ctx->jsonUrl);

        return new FontsFinalizeResult(success: true, fonts: $ctx->fonts);
    },
);

return json_response($result->toResponse());

onFinalize для fonts можно не передавать, если сайту достаточно того, что SDK сохранил файлы и вернул Verstka дерево fonts с публичными URL.

5. Использовать framework adapters

Если вы не хотите вручную писать callback route, используйте готовый адаптер для вашего framework. Он регистрирует один callback endpoint и сам выбирает обработку по event: article_saved или site_fonts_updated.

FrameworkЧто дает SDK
SymfonyBundle, DI configuration, CallbackController, exception subscriber.
LaravelService provider, config publish, auto route POST /verstka/callback, exception renderer.

Metadata

metadata - это необязательный массив или JSON-строка, которую сайт передает при открытии редактора. Verstka сохранит эти данные в сессии и вернет в callback.

Metadata удобно использовать для данных, которые помогут сайту обработать сохранение:

  • ID пользователя в CMS;
  • ID раздела, бренда или проекта;
  • флаги окружения;
  • короткоживущий токен для дополнительной проверки прав;
  • данные для basic авторизации или bearer token;
  • конфигурация Custom Containers.
php
$editorUrl = $client->getEditorUrl(
    materialId: (string) $article->id,
    vmsJson: $article->vms_json,
    metadata: [
        'editor_user_id' => (string) $user->id,
        'section_id' => (string) $article->section_id,
        'customContainers' => [],
    ],
);

SDK автоматически добавляет version: "php_<sdk-version>".

Не используйте metadata как произвольное хранилище секретов, приватных ключей или персональных данных, которые не нужны callback-обработчику. Полное описание: metadata.

PreSave hooks

processMaterialCallback и processFontsCallback принимают опциональный onPreSave. Hook вызывается после проверки подписи, но до скачивания ZIP. Это место для проверки прав, блокировок и лимитов, основываясь на метаданных callback.

php
use Verstka\Sdk\Finalize\ContentPreSaveContext;
use Verstka\Sdk\Finalize\PreSaveDecision;

$result = $client->processMaterialCallback(
    callbackData: $requestPayload,
    signature: $signature,
    storage: $storage,
    onFinalize: $onFinalize,
    onPreSave: function (ContentPreSaveContext $ctx): PreSaveDecision {
        if (!UserPolicy::canSave($ctx->metadata['timeLimitedAuthToken'] ?? null, $ctx->materialId)) {
            return new PreSaveDecision(allow: false, reason: 'Access denied');
        }

        return new PreSaveDecision(allow: true);
    },
);

Если allow=false, SDK не скачивает ZIP, файлы не пишутся, Verstka получает rc: 0.

Callback authorization

Если callback URL сайта защищен Basic Auth или Bearer token, передайте служебные ключи в metadata при открытии редактора.

Basic Auth:

php
metadata: [
    'webhook_auth_user' => 'callback-user',
    'webhook_auth_password' => 'callback-password',
],

Bearer token:

php
metadata: [
    'webhook_auth_user' => 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...',
],

Verstka добавит заголовок Authorization к исходящему callback. Подробнее: Callback Authorization.

Справочник методов

МетодНазначение
VerstkaClient::getEditorUrl(...)Открывает сессию через POST /session/open и возвращает URL редактора.
VerstkaClient::processMaterialCallback(...)Обрабатывает article_saved: подпись, ZIP, медиа, onFinalize.
VerstkaClient::processFontsCallback(...)Обрабатывает site_fonts_updated: подпись, fonts ZIP, font files, manifests.
StorageAdapter::saveMedia(...)Сохраняет файл из vms_media/* и возвращает публичный URL.
StorageAdapter::saveFontFile(...)Сохраняет файл шрифта и возвращает публичный URL.
StorageAdapter::saveFontsManifest(...)Сохраняет vms_fonts.css или vms_fonts.json и возвращает URL.
LocalStorageAdapterФайловая reference-реализация storage adapter.
SignatureService::signMaterial(...)Строит HMAC для material_id:url.
SignatureService::verifySignature(...)Проверяет HMAC.
UrlBuilder::buildAuthorizedContentUrl(...)Добавляет api_key и material_id к content_url.