initial backup script

This commit is contained in:
Robin Appelman 2017-06-10 13:48:42 +02:00
commit d5896cc6f3
6 changed files with 147 additions and 0 deletions

3
.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
.env
vendor
composer.lock

27
backup.php Normal file
View file

@ -0,0 +1,27 @@
<?php declare(strict_types=1);
require 'vendor/autoload.php';
if (!getenv('STORAGE_ROOT')) {
$env = new \Dotenv\Dotenv(__DIR__);
$env->load();
}
$store = new \Demostf\Backup\Store(getenv('STORAGE_ROOT'));
$source = new \Demostf\Backup\Source(getenv('SOURCE'));
$statePath = getenv('STATE_FILE');
if (file_exists($statePath)) {
$lastPage = intval(file_get_contents($statePath));
if (!$lastPage) {
$lastPage = 1;
}
} else {
$lastPage = 1;
}
$backup = new \Demostf\Backup\Backup($source, $store);
$currentPage = $backup->backupFrom($lastPage);
file_put_contents($statePath, $currentPage);

11
composer.json Normal file
View file

@ -0,0 +1,11 @@
{
"autoload": {
"psr-4": {
"Demostf\\Backup\\": "src/",
"Demostf\\Backup\\Test\\": "tests/"
}
},
"require": {
"vlucas/phpdotenv": "^2.4"
}
}

50
src/Backup.php Normal file
View file

@ -0,0 +1,50 @@
<?php declare(strict_types=1);
namespace Demostf\Backup;
class Backup {
const SUCCESS = 1;
const FAIL = -1;
const EMPTY_PAGE = 0;
private $source;
private $store;
public function __construct(Source $source, Store $store) {
$this->source = $source;
$this->store = $store;
}
private function backupDemo(string $name, string $url, string $hash): bool {
$handle = fopen($url, 'r');
$storedHash = $this->store->store($name, $handle);
return $hash === '' || $hash === $storedHash;
}
public function backupPage(int $page): int {
$demos = $this->source->listDemos($page, 'ASC');
if (count($demos) === 0) {
return self::EMPTY_PAGE;
}
foreach ($demos as $demo) {
$url = $demo['url'];
$name = basename($url);
if (!$this->store->exists($name)) {
if (!$this->backupDemo($name, $url, $demo['hash'])) {
echo "hash mismatch\n";
return self::FAIL;
}
}
}
return self::SUCCESS;
}
public function backupFrom(int $startPage): int {
$currentPage = $startPage;
while ($this->backupPage($currentPage) === self::SUCCESS) {
$currentPage++;
}
return $currentPage;
}
}

23
src/Source.php Normal file
View file

@ -0,0 +1,23 @@
<?php declare(strict_types=1);
namespace Demostf\Backup;
class Source {
private $endpoint;
public function __construct($endpoint) {
$this->endpoint = $endpoint;
}
public function listDemos(int $page = 0, string $order = 'DESC'): array {
$url = $this->endpoint . '/demos?page=' . $page . '&order=' . $order;
$content = file_get_contents($url);
$demos = json_decode($content, true);
foreach ($demos as $data) {
$date = new \DateTime();
$date->setTimestamp($data['time']);
$data['time'] = $date;
}
return $demos;
}
}

33
src/Store.php Normal file
View file

@ -0,0 +1,33 @@
<?php declare(strict_types=1);
namespace Demostf\Backup;
class Store {
private $baseDir;
public function __construct($baseDir) {
$this->baseDir = $baseDir;
}
public function store(string $name, $handle): string {
$path = $this->generatePath($name);
if (!is_dir(dirname($path))) {
mkdir(dirname($path), 0775, true);
}
file_put_contents($path, $handle);
echo "$name\n";
return md5_file($path);
}
private function generatePath(string $name): string {
return $this->baseDir . $this->getPrefix($name) . $name;
}
private function getPrefix(string $name): string {
return '/' . substr($name, 0, 2) . '/' . substr($name, 2, 2) . '/';
}
public function exists(string $name): bool {
return file_exists($this->generatePath($name));
}
}