96 lines
2.5 KiB
PHP
96 lines
2.5 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Import;
|
|
|
|
use RuntimeException;
|
|
|
|
final class ImportJobStore
|
|
{
|
|
public function __construct(
|
|
private readonly string $storageDir = '',
|
|
) {
|
|
}
|
|
|
|
public function create(array $state): string
|
|
{
|
|
$token = bin2hex(random_bytes(16));
|
|
$state['token'] = $token;
|
|
$this->write($token, $state);
|
|
|
|
return $token;
|
|
}
|
|
|
|
public function get(string $token): ?array
|
|
{
|
|
$path = $this->path($token);
|
|
if (!is_file($path)) {
|
|
return null;
|
|
}
|
|
|
|
$contents = file_get_contents($path);
|
|
if ($contents === false || $contents === '') {
|
|
return null;
|
|
}
|
|
|
|
$state = json_decode($contents, true);
|
|
if (!is_array($state)) {
|
|
throw new RuntimeException('The import job state is corrupt.');
|
|
}
|
|
|
|
return $state;
|
|
}
|
|
|
|
public function save(string $token, array $state): void
|
|
{
|
|
$state['token'] = $token;
|
|
$this->write($token, $state);
|
|
}
|
|
|
|
public function delete(string $token): void
|
|
{
|
|
$path = $this->path($token);
|
|
if (is_file($path)) {
|
|
@unlink($path);
|
|
}
|
|
}
|
|
|
|
public function pathForToken(string $token): string
|
|
{
|
|
return $this->path($token);
|
|
}
|
|
|
|
private function write(string $token, array $state): void
|
|
{
|
|
$path = $this->path($token);
|
|
$dir = dirname($path);
|
|
if (!is_dir($dir) && !mkdir($dir, 0777, true) && !is_dir($dir)) {
|
|
throw new RuntimeException('Unable to create the import job storage directory.');
|
|
}
|
|
|
|
$json = json_encode($state, JSON_THROW_ON_ERROR | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
|
|
$tmpPath = $path . '.' . bin2hex(random_bytes(6)) . '.tmp';
|
|
if (file_put_contents($tmpPath, $json) === false) {
|
|
throw new RuntimeException('Unable to write the import job state.');
|
|
}
|
|
|
|
if (!@rename($tmpPath, $path)) {
|
|
@unlink($tmpPath);
|
|
throw new RuntimeException('Unable to persist the import job state.');
|
|
}
|
|
}
|
|
|
|
private function path(string $token): string
|
|
{
|
|
$safeToken = preg_replace('/[^a-zA-Z0-9_-]/', '', $token);
|
|
if ($safeToken === '') {
|
|
throw new RuntimeException('Invalid import job token.');
|
|
}
|
|
|
|
$storageDir = $this->storageDir !== '' ? $this->storageDir : sys_get_temp_dir() . '/warner-import-jobs';
|
|
|
|
return rtrim($storageDir, '/\\') . '/' . $safeToken . '.json';
|
|
}
|
|
}
|