KMP PHP API Reference

BackupService
in package

Database-agnostic backup and restore service.

Exports all application tables via direct database reads as JSON, compresses with gzip, and encrypts with AES-256-GCM. Restore reverses the process.

Table of Contents

Constants

CIPHER  : mixed = 'aes-256-gcm'
EXCLUDED_TABLES  : mixed = ['queued_jobs', 'queue_processes', 'backups', '...
Tables excluded from backup because they contain transient runtime state.
FORMAT_VERSION  : mixed = 2
HEADER_PREFIX_LENGTH  : mixed = 1048576
IV_LENGTH  : mixed = 12
OPERATIONAL_SCHEMA_TABLES  : mixed = ['backups', 'queued_jobs', 'queue_processes', '...
Runtime tables whose rows are excluded but schemas must be preserved.
PBKDF2_ALGO  : mixed = 'sha256'
PBKDF2_ITERATIONS  : mixed = 100000
SALT_LENGTH  : mixed = 16
TAG_LENGTH  : mixed = 16

Properties

$connectionName  : string

Methods

__construct()  : mixed
decryptToLogicalArchive()  : string
Decrypt a passphrase-protected backup into its logical archive.
encryptLogicalArchive()  : string
Protect a managed logical archive with a temporary tenant restore credential.
export()  : array{data: string, meta: array}
Export all application tables to an encrypted backup file.
exportLogicalArchive()  : array{data: string, meta: array{table_count: int, row_count: int, size_bytes: int}}
Export all application tables as a gzip-compressed JSON logical archive.
getMigrationFingerprint()  : array<string, array<int, array{version: string, migration_name: string}>>
Snapshot migration state for fingerprinting a backup.
import()  : array{table_count: int, row_count: int, constraints_not_valid?: int, payload_upgrade?: array, post_restore?: array}
Import (restore) from an encrypted backup.
importLogicalArchive()  : array{table_count: int, row_count: int, constraints_not_valid?: int, payload_upgrade?: array, post_restore?: array}
Import a gzip-compressed JSON logical archive.
validateImportHeader()  : void
Validate that an encrypted backup starts with the expected JSON metadata.
validateImportPayload()  : void
Validate that an encrypted backup can be opened before starting restore side effects.
validateLogicalArchive()  : void
Validate a gzip-compressed JSON logical archive without restoring it.
buildRestoreTableMap()  : array<string, array<int, array<string, mixed>>>
Build restore table map for the current schema.
clearApplicationCachesForRestore()  : void
Clear Cake cache pools around restore so schema and runtime state match DB.
connection()  : Connection
Return the configured backup target connection.
decodeLogicalPayload()  : array{meta: array, schema: array, tables: array}
decrypt()  : string
Decrypt data encrypted by encrypt().
deriveKey()  : string
Derive a 256-bit key from a passphrase using PBKDF2.
describeFingerprintDiff()  : string
Build a short human-readable diff between backup and current migration fingerprints for error messages.
dropPostgresForeignKeys()  : array<int, array{table: string, name: string, definition: string}>
Drop FK constraints for Postgres tables and return definitions for later re-add.
encrypt()  : string
Encrypt data with AES-256-GCM using a PBKDF2-derived key.
ensureOperationalSchemaTables()  : array{meta: array, schema: array, tables: array}
Add operational table definitions that older backup manifests omitted.
filterRowsToCurrentColumns()  : array<int, array<string, mixed>>
Drop columns that existed in the backup environment but no longer exist in the current schema.
getInsertBatchSize()  : int
Get insert batch size.
importPayloadRows()  : array{table_count: int, row_count: int}
insertBatchRows()  : void
isExcludedTable()  : bool
Return true when the table should never appear in a backup payload.
isIntegerLikeType()  : bool
Check if integer like type.
isNumericColumnType()  : bool
Check if numeric column type.
normalizeBooleanForPostgres()  : mixed
Normalize Postgres boolean column values from mixed JSON payload forms.
normalizeColumnScalarForMysql()  : mixed
Coerce scalar values into DB-safe representations for MySQL inserts.
normalizeComplexValueForMysql()  : array{converted: bool, value: mixed}
Coerce array/object values for MySQL inserts.
normalizeEmptyStringForMysql()  : array{converted: bool, value: mixed}
Coerce empty-string values for MySQL numeric/boolean/temporal columns.
normalizeNullForMysql()  : array{converted: bool, value: mixed}
Coerce nulls for non-nullable MySQL columns.
normalizeRowForInsert()  : array<string, mixed>
Normalize row values for MySQL inserts, coercing temporal values from ISO-8601 JSON forms to DB-friendly SQL literal formats.
normalizeTemporalValueForMysql()  : string|null
Convert ISO-8601 temporal strings to MySQL-compatible temporal formats.
readGzipPrefix()  : string
Decompress only the requested prefix without expanding the full archive.
reportProgress()  : void
reportSchemaMismatch()  : void
resetPostgresSequences()  : void
Reset Postgres sequences so new rows follow restored primary keys.
restorePostgresForeignKeys()  : int
Re-add previously dropped Postgres FK constraints.
validateLogicalArchiveHeader()  : void
Validate the bounded header of a compressed logical archive.

Constants

EXCLUDED_TABLES

Tables excluded from backup because they contain transient runtime state.

private mixed EXCLUDED_TABLES = ['queued_jobs', 'queue_processes', 'backups', 'sessions']

Queue state, backup metadata, and session tokens should not cross environments. Phinx migration logs are intentionally preserved so a restored database keeps accurate main/plugin migration history.

HEADER_PREFIX_LENGTH

private mixed HEADER_PREFIX_LENGTH = 1048576

OPERATIONAL_SCHEMA_TABLES

Runtime tables whose rows are excluded but schemas must be preserved.

private mixed OPERATIONAL_SCHEMA_TABLES = ['backups', 'queued_jobs', 'queue_processes', 'sessions']

Properties

$connectionName read-only

private string $connectionName = 'default'

Methods

__construct()

public __construct([string $connectionName = 'default' ]) : mixed
Parameters
$connectionName : string = 'default'

CakePHP connection name to back up or restore.

decryptToLogicalArchive()

Decrypt a passphrase-protected backup into its logical archive.

public decryptToLogicalArchive(string $encryptedData, string $encryptionKey) : string

Used by the platform legacy-import path to convert a .kmpbackup (upstream/self-service format) into a managed envelope-encrypted backup.

Parameters
$encryptedData : string
$encryptionKey : string
Return values
string

encryptLogicalArchive()

Protect a managed logical archive with a temporary tenant restore credential.

public encryptLogicalArchive(string $compressedData, string $encryptionKey) : string
Parameters
$compressedData : string
$encryptionKey : string
Return values
string

export()

Export all application tables to an encrypted backup file.

public export(string $encryptionKey) : array{data: string, meta: array}
Parameters
$encryptionKey : string

User-provided encryption key

Return values
array{data: string, meta: array}

Encrypted bytes and metadata

exportLogicalArchive()

Export all application tables as a gzip-compressed JSON logical archive.

public exportLogicalArchive() : array{data: string, meta: array{table_count: int, row_count: int, size_bytes: int}}

Encryption is intentionally left to the caller so managed platform backups can use per-backup envelope keys without double encryption.

Return values
array{data: string, meta: array{table_count: int, row_count: int, size_bytes: int}}

getMigrationFingerprint()

Snapshot migration state for fingerprinting a backup.

public getMigrationFingerprint() : array<string, array<int, array{version: string, migration_name: string}>>

Returns a map of phinxlog-table-name → array of {version, migration_name} rows sorted by version. The structure stays stable across engines so the fingerprint can be compared between the bake environment (e.g. MySQL) and the restore environment (e.g. Postgres).

Return values
array<string, array<int, array{version: string, migration_name: string}>>

import()

Import (restore) from an encrypted backup.

public import(string $encryptedData, string $encryptionKey[, callable(array<string, mixed>): void|null $progressReporter = null ][, callable|array{ignoreSchemaMismatch?: bool}|null $options = [] ][, callable(): void|null $migrationRunner = null ]) : array{table_count: int, row_count: int, constraints_not_valid?: int, payload_upgrade?: array, post_restore?: array}
Parameters
$encryptedData : string

Raw encrypted backup bytes

$encryptionKey : string

User-provided encryption key

$progressReporter : callable(array<string, mixed>): void|null = null

Restore progress callback

$options : callable|array{ignoreSchemaMismatch?: bool}|null = []

Restore options, or migration runner for BC

$migrationRunner : callable(): void|null = null

Post-import migration callback

Return values
array{table_count: int, row_count: int, constraints_not_valid?: int, payload_upgrade?: array, post_restore?: array}

Import statistics

importLogicalArchive()

Import a gzip-compressed JSON logical archive.

public importLogicalArchive(string $compressedData[, callable(array<string, mixed>): void|null $progressReporter = null ][, callable|array{ignoreSchemaMismatch?: bool}|null $options = [] ][, callable(): void|null $migrationRunner = null ]) : array{table_count: int, row_count: int, constraints_not_valid?: int, payload_upgrade?: array, post_restore?: array}
Parameters
$compressedData : string

Gzip-compressed versioned JSON payload

$progressReporter : callable(array<string, mixed>): void|null = null

Restore progress callback

$options : callable|array{ignoreSchemaMismatch?: bool}|null = []

Restore options, or migration runner for BC

$migrationRunner : callable(): void|null = null

Post-import migration callback

Return values
array{table_count: int, row_count: int, constraints_not_valid?: int, payload_upgrade?: array, post_restore?: array}

validateImportHeader()

Validate that an encrypted backup starts with the expected JSON metadata.

public validateImportHeader(string $encryptedData, string $encryptionKey) : void

This intentionally avoids full JSON decoding in web requests; the queued restore task performs full validation before making restore changes.

Parameters
$encryptedData : string
$encryptionKey : string

validateImportPayload()

Validate that an encrypted backup can be opened before starting restore side effects.

public validateImportPayload(string $encryptedData, string $encryptionKey) : void

This decrypts, decompresses, and validates the payload structure only; it does not reset schema, write rows, queue work, or mutate restore status.

Parameters
$encryptedData : string
$encryptionKey : string

validateLogicalArchive()

Validate a gzip-compressed JSON logical archive without restoring it.

public validateLogicalArchive(string $compressedData) : void
Parameters
$compressedData : string

buildRestoreTableMap()

Build restore table map for the current schema.

private buildRestoreTableMap(array<string, array<int, array<string, mixed>>> $payloadTables, array<int, string> $currentTables) : array<string, array<int, array<string, mixed>>>

A backup is a full logical snapshot. When an older backup is restored into a newer schema, tables introduced after the backup was taken must be emptied so stale current-environment data cannot survive the restore. Tables that no longer exist in the current schema are left in the decoded payload for compatibility migrators, but they are not inserted directly.

Parameters
$payloadTables : array<string, array<int, array<string, mixed>>>
$currentTables : array<int, string>
Return values
array<string, array<int, array<string, mixed>>>

clearApplicationCachesForRestore()

Clear Cake cache pools around restore so schema and runtime state match DB.

private clearApplicationCachesForRestore() : void

connection()

Return the configured backup target connection.

private connection() : Connection
Return values
Connection

decodeLogicalPayload()

private decodeLogicalPayload(string $compressedData[, callable(array<string, mixed>): void|null $progressReporter = null ]) : array{meta: array, schema: array, tables: array}
Parameters
$compressedData : string
$progressReporter : callable(array<string, mixed>): void|null = null
Return values
array{meta: array, schema: array, tables: array}

decrypt()

Decrypt data encrypted by encrypt().

private decrypt(string $data, string $passphrase) : string
Parameters
$data : string
$passphrase : string
Return values
string

deriveKey()

Derive a 256-bit key from a passphrase using PBKDF2.

private deriveKey(string $passphrase, string $salt) : string
Parameters
$passphrase : string
$salt : string
Return values
string

describeFingerprintDiff()

Build a short human-readable diff between backup and current migration fingerprints for error messages.

private describeFingerprintDiff(array<string, array<int, array{version: string, migration_name: string}>> $backup, array<string, array<int, array{version: string, migration_name: string}>> $current) : string
Parameters
$backup : array<string, array<int, array{version: string, migration_name: string}>>
$current : array<string, array<int, array{version: string, migration_name: string}>>
Return values
string

dropPostgresForeignKeys()

Drop FK constraints for Postgres tables and return definitions for later re-add.

private dropPostgresForeignKeys(mixed $connection, mixed $driver, array<int, string> $tableNames) : array<int, array{table: string, name: string, definition: string}>
Parameters
$connection : mixed
$driver : mixed
$tableNames : array<int, string>
Return values
array<int, array{table: string, name: string, definition: string}>

encrypt()

Encrypt data with AES-256-GCM using a PBKDF2-derived key.

private encrypt(string $data, string $passphrase) : string

Output format: salt(16) + iv(12) + tag(16) + ciphertext

Parameters
$data : string
$passphrase : string
Return values
string

ensureOperationalSchemaTables()

Add operational table definitions that older backup manifests omitted.

private ensureOperationalSchemaTables(array{meta: array, schema: array, tables: array$payload) : array{meta: array, schema: array, tables: array}

The rows remain excluded from the restore payload, but preserving table shapes keeps runtime services usable after schema reset.

Parameters
$payload : array{meta: array, schema: array, tables: array}
Return values
array{meta: array, schema: array, tables: array}

filterRowsToCurrentColumns()

Drop columns that existed in the backup environment but no longer exist in the current schema.

private filterRowsToCurrentColumns(array<int, array<string, mixed>> $rows, TableSchemaInterface $tableSchema) : array<int, array<string, mixed>>
Parameters
$rows : array<int, array<string, mixed>>
$tableSchema : TableSchemaInterface
Return values
array<int, array<string, mixed>>

getInsertBatchSize()

Get insert batch size.

private getInsertBatchSize(int $columnCount, bool $isPostgres) : int
Parameters
$columnCount : int
$isPostgres : bool
Return values
int

importPayloadRows()

private importPayloadRows(array{schema: array, tables: array$payload[, callable(array<string, mixed>): void|null $progressReporter = null ]) : array{table_count: int, row_count: int}
Parameters
$payload : array{schema: array, tables: array}
$progressReporter : callable(array<string, mixed>): void|null = null
Return values
array{table_count: int, row_count: int}

insertBatchRows()

private insertBatchRows(mixed $connection, mixed $driver, string $quotedTable, array<int, string> $columns, array<int, array<string, mixed>> $batch, TableSchemaInterface $tableSchema, bool $isPostgres) : void
Parameters
$connection : mixed
$driver : mixed
$quotedTable : string
$columns : array<int, string>
$batch : array<int, array<string, mixed>>
$tableSchema : TableSchemaInterface
$isPostgres : bool

isExcludedTable()

Return true when the table should never appear in a backup payload.

private static isExcludedTable(string $tableName) : bool
Parameters
$tableName : string
Return values
bool

isIntegerLikeType()

Check if integer like type.

private isIntegerLikeType(string $columnType) : bool
Parameters
$columnType : string
Return values
bool

isNumericColumnType()

Check if numeric column type.

private isNumericColumnType(string $columnType) : bool
Parameters
$columnType : string
Return values
bool

normalizeBooleanForPostgres()

Normalize Postgres boolean column values from mixed JSON payload forms.

private normalizeBooleanForPostgres(TableSchemaInterface $tableSchema, string $column, mixed $value) : mixed
Parameters
$tableSchema : TableSchemaInterface
$column : string
$value : mixed

normalizeColumnScalarForMysql()

Coerce scalar values into DB-safe representations for MySQL inserts.

private normalizeColumnScalarForMysql(mixed $value, string $columnType) : mixed
Parameters
$value : mixed
$columnType : string

normalizeComplexValueForMysql()

Coerce array/object values for MySQL inserts.

private normalizeComplexValueForMysql(mixed $value, string $columnType) : array{converted: bool, value: mixed}
Parameters
$value : mixed
$columnType : string
Return values
array{converted: bool, value: mixed}

normalizeEmptyStringForMysql()

Coerce empty-string values for MySQL numeric/boolean/temporal columns.

private normalizeEmptyStringForMysql(TableSchemaInterface $tableSchema, string $column, string $columnType) : array{converted: bool, value: mixed}
Parameters
$tableSchema : TableSchemaInterface
$column : string
$columnType : string
Return values
array{converted: bool, value: mixed}

normalizeNullForMysql()

Coerce nulls for non-nullable MySQL columns.

private normalizeNullForMysql(TableSchemaInterface $tableSchema, string $column, string $columnType) : array{converted: bool, value: mixed}
Parameters
$tableSchema : TableSchemaInterface
$column : string
$columnType : string
Return values
array{converted: bool, value: mixed}

normalizeRowForInsert()

Normalize row values for MySQL inserts, coercing temporal values from ISO-8601 JSON forms to DB-friendly SQL literal formats.

private normalizeRowForInsert(array<string, mixed> $row, array<int, string> $columns, TableSchemaInterface $tableSchema, bool $isPostgres) : array<string, mixed>
Parameters
$row : array<string, mixed>
$columns : array<int, string>
$tableSchema : TableSchemaInterface
$isPostgres : bool
Return values
array<string, mixed>

normalizeTemporalValueForMysql()

Convert ISO-8601 temporal strings to MySQL-compatible temporal formats.

private normalizeTemporalValueForMysql(string $value, string $columnType) : string|null
Parameters
$value : string
$columnType : string
Return values
string|null

readGzipPrefix()

Decompress only the requested prefix without expanding the full archive.

private readGzipPrefix(string $compressedData, int $maxLength) : string
Parameters
$compressedData : string
$maxLength : int
Return values
string

reportProgress()

private reportProgress(callable(array<string, mixed>): void|null $progressReporter, string $phase, string $message[, array<string, mixed> $context = [] ]) : void
Parameters
$progressReporter : callable(array<string, mixed>): void|null
$phase : string
$message : string
$context : array<string, mixed> = []

reportSchemaMismatch()

private reportSchemaMismatch(array<string, mixed> $payload, bool $ignoreSchemaMismatch[, callable(array<string, mixed>): void|null $progressReporter = null ]) : void
Parameters
$payload : array<string, mixed>
$ignoreSchemaMismatch : bool
$progressReporter : callable(array<string, mixed>): void|null = null

resetPostgresSequences()

Reset Postgres sequences so new rows follow restored primary keys.

private resetPostgresSequences(Connection $connection, mixed $schemaCollection, mixed $driver, array<int, string> $tableNames) : void
Parameters
$connection : Connection
$schemaCollection : mixed
$driver : mixed
$tableNames : array<int, string>

restorePostgresForeignKeys()

Re-add previously dropped Postgres FK constraints.

private restorePostgresForeignKeys(mixed $connection, mixed $driver, array<int, array{table: string, name: string, definition: string}> $droppedForeignKeys) : int
Parameters
$connection : mixed
$driver : mixed
$droppedForeignKeys : array<int, array{table: string, name: string, definition: string}>
Return values
int

validateLogicalArchiveHeader()

Validate the bounded header of a compressed logical archive.

private validateLogicalArchiveHeader(string $compressedData) : void
Parameters
$compressedData : string
On this page

Search results