Update for PHP 8.2

This commit is contained in:
David Fairbanks 2023-07-25 13:23:01 -04:00
parent 40616f8346
commit 91976bbc02
Signed by: david-fairbanks42
GPG Key ID: 23A5FB8E1952978F
6 changed files with 95 additions and 102 deletions

View File

@ -4,6 +4,10 @@ Stand-alone script designed to run via cron or systemd to back-up EC2 volumes on
All volumes associated with the EC2 instance are backed up. All volumes associated with the EC2 instance are backed up.
This script does not freeze the volume or a database or wait for inactivity. It just creates snapshots. High traffic
servers should not use this as their only means of backup since there is a chance the database could be mid-write
during the snapshot start which will break the database.
## Usage ## Usage
After the required configuration settings are set up in the `.env` file, simply executing `php backup.php` will After the required configuration settings are set up in the `.env` file, simply executing `php backup.php` will
perform the backup. The script has additional options such as `--no-prune` to prevent the script from removing old perform the backup. The script has additional options such as `--no-prune` to prevent the script from removing old
@ -89,4 +93,5 @@ WantedBy=timers.target
``` ```
To activate the schedule, execute the command (noting the sudo use) To activate the schedule, execute the command (noting the sudo use)
`sudo systemctl start ec2-backup.timer` `sudo systemctl start ec2-backup.timer`

View File

@ -1,10 +1,8 @@
<?php <?php
/** /**
* Date Helper * Dates.php
* *
* @package Fairbanks\Kizarian\Utilities * @copyright 2023 Fairbanks Publishing LLC
* @copyright (c) 2018, Fairbanks Publishing
* @license Proprietary
*/ */
namespace App; namespace App;
@ -26,11 +24,11 @@ class Dates {
* *
* @return Carbon * @return Carbon
*/ */
public static function makeCarbon($date, Carbon $default=null) public static function makeCarbon(mixed $date, Carbon $default=null): Carbon
{ {
if(is_object($date) && $date instanceof Carbon) { if ($date instanceof Carbon) {
return $date; return $date;
} elseif(is_object($date) && $date instanceof \DateTime) { } elseif ($date instanceof \DateTime) {
return Carbon::instance($date); return Carbon::instance($date);
} elseif (is_object($date)) { } elseif (is_object($date)) {
return Carbon::parse($date->date, $date->timezone); return Carbon::parse($date->date, $date->timezone);

View File

@ -1,9 +1,8 @@
<?php <?php
/** /**
* (file name) * Ec2Backup.php
* *
* @copyright (c) 2019, Fairbanks Publishing * @copyright 2023 Fairbanks Publishing LLC
* @license Proprietary
*/ */
namespace App; namespace App;
@ -21,19 +20,19 @@ class Ec2Backup
/** /**
* @var Ec2Client * @var Ec2Client
*/ */
private $ec2Client; private Ec2Client $ec2Client;
/** /**
* @var boolean * @var boolean
*/ */
private $enable = true; private bool $enable = true;
/** /**
* Number of completed backups to keep * Number of completed backups to keep
* This is the number BEFORE a backup is started * This is the number BEFORE a backup is started
* @var int * @var int
*/ */
private $maxBackupCount = 4; private int $maxBackupCount = 4;
public function __construct(Ec2Client $ec2Client) { public function __construct(Ec2Client $ec2Client) {
$this->ec2Client = $ec2Client; $this->ec2Client = $ec2Client;
@ -45,11 +44,11 @@ class Ec2Backup
$this->maxBackupCount = 4; $this->maxBackupCount = 4;
} }
public function create(array $options=[]) public function create(array $options=[]): void
{ {
$options = array_merge(['noPrune' => false, 'force' => false], $options); $options = array_merge(['noPrune' => false, 'force' => false], $options);
if($this->enable == false && $options['force'] != true) { if (!$this->enable && !$options['force']) {
app_echo('EC2 Backup is disabled in environment'); app_echo('EC2 Backup is disabled in environment');
return; return;
} }
@ -78,7 +77,7 @@ class Ec2Backup
$tags = $this->getTags($machine['instanceId']); $tags = $this->getTags($machine['instanceId']);
foreach ($volumes as $volume) { foreach ($volumes as $volume) {
if($options['noPrune'] == true) { if ($options['noPrune']) {
$pruneWording = '(pruning disabled)'; $pruneWording = '(pruning disabled)';
} else { } else {
$pruneCount = $this->pruneBackups($volume['volumeId']); $pruneCount = $this->pruneBackups($volume['volumeId']);
@ -89,8 +88,7 @@ class Ec2Backup
if (count($volumes) > 1) if (count($volumes) > 1)
$name .= " ({$volume['device']})"; $name .= " ({$volume['device']})";
$r = $this->backup(['volumeId' => $volume['volumeId'], 'name' => $name]); if ($this->backup(['volumeId' => $volume['volumeId'], 'name' => $name])) {
if($r == true) {
app_echo("Successfully started snapshot for {$volume['volumeId']} {$pruneWording}"); app_echo("Successfully started snapshot for {$volume['volumeId']} {$pruneWording}");
} else { } else {
app_echo("Error starting snapshot for {$volume['volumeId']} {$pruneWording}"); app_echo("Error starting snapshot for {$volume['volumeId']} {$pruneWording}");
@ -98,7 +96,7 @@ class Ec2Backup
} }
} }
public function getVolumes($instanceId) public function getVolumes($instanceId): array
{ {
try { try {
$result = $this->ec2Client->describeVolumes( $result = $this->ec2Client->describeVolumes(
@ -128,7 +126,7 @@ class Ec2Backup
return $volumes; return $volumes;
} }
public function getTags($instanceId) public function getTags($instanceId): array
{ {
try { try {
$result = $this->ec2Client->describeTags( $result = $this->ec2Client->describeTags(
@ -155,7 +153,7 @@ class Ec2Backup
return $tags; return $tags;
} }
public function getBackups($volumeId) public function getBackups($volumeId): array
{ {
try { try {
$result = $this->ec2Client->describeSnapshots( $result = $this->ec2Client->describeSnapshots(
@ -182,7 +180,7 @@ class Ec2Backup
$snapshots[$snapshot['SnapshotId']] = [ $snapshots[$snapshot['SnapshotId']] = [
'started' => Dates::makeCarbon($snapshot['StartTime']), 'started' => Dates::makeCarbon($snapshot['StartTime']),
'description' => $snapshot['Description'], 'description' => $snapshot['Description'],
'snapshotId' => $snapshot['SnapshotId'] 'snapshotId' => $snapshot['SnapshotId'],
]; ];
} }
@ -197,16 +195,18 @@ class Ec2Backup
return $snapshots; return $snapshots;
} }
public function pruneBackups($volumeId) public function pruneBackups($volumeId): int
{ {
$backups = $this->getBackups($volumeId); $backups = $this->getBackups($volumeId);
if(count($backups) <= $this->maxBackupCount) if (count($backups) <= $this->maxBackupCount) {
return 0; return 0;
}
$prune = array_slice($backups, 0, count($backups) - $this->maxBackupCount); $prune = array_slice($backups, 0, count($backups) - $this->maxBackupCount);
if(empty($prune)) if(empty($prune)) {
return 0; return 0;
}
$count = 0; $count = 0;
foreach ($prune as $snapshotId => $snapshot) { foreach ($prune as $snapshotId => $snapshot) {
@ -228,7 +228,7 @@ class Ec2Backup
return $count; return $count;
} }
public function backup(array $params) public function backup(array $params): bool
{ {
if (!isset($params['volumeId'])) { if (!isset($params['volumeId'])) {
app_echo('Volume ID is not set in backup parameters'); app_echo('Volume ID is not set in backup parameters');

View File

@ -1,9 +1,8 @@
<?php <?php
/** /**
* Machine Details for Logging * MachineDetails.php
* *
* @copyright (c) 2017, Fairbanks Publishing * @copyright 2023 Fairbanks Publishing LLC
* @license Proprietary
*/ */
namespace App; namespace App;
@ -19,12 +18,12 @@ class MachineDetails
/** /**
* @var MachineDetails * @var MachineDetails
*/ */
protected static $instance; protected static MachineDetails $instance;
/** /**
* @var array * @var array
*/ */
protected static $details = [ protected static array $details = [
'type' => null, 'type' => null,
'id' => null, 'id' => null,
'machineId' => null, 'machineId' => null,
@ -36,14 +35,14 @@ class MachineDetails
/** /**
* PHP config setting for default_socket_timeout to reset to after doing file_get_contents() * PHP config setting for default_socket_timeout to reset to after doing file_get_contents()
* @var int * @var int|null
*/ */
protected $socketTimeout = null; protected ?int $socketTimeout = null;
/** /**
* @return MachineDetails * @return MachineDetails
*/ */
public static function getInstance() public static function getInstance(): MachineDetails
{ {
if (!isset(static::$instance)) { if (!isset(static::$instance)) {
static::$instance = new static; static::$instance = new static;
@ -55,7 +54,7 @@ class MachineDetails
/** /**
* @return array * @return array
*/ */
public static function getDetails() public static function getDetails(): array
{ {
if(self::$instance === null) if(self::$instance === null)
self::$instance = self::getInstance(); self::$instance = self::getInstance();
@ -66,7 +65,7 @@ class MachineDetails
/** /**
* @return string|null * @return string|null
*/ */
public static function id() public static function id(): ?string
{ {
if(self::$instance === null) if(self::$instance === null)
self::$instance = self::getInstance(); self::$instance = self::getInstance();
@ -77,7 +76,7 @@ class MachineDetails
/** /**
* @return string|null * @return string|null
*/ */
public static function machineId() public static function machineId(): ?string
{ {
if(self::$instance === null) if(self::$instance === null)
self::$instance = self::getInstance(); self::$instance = self::getInstance();
@ -88,7 +87,7 @@ class MachineDetails
/** /**
* @return string * @return string
*/ */
public static function fullMachineId() public static function fullMachineId(): string
{ {
if(self::$instance === null) if(self::$instance === null)
self::$instance = self::getInstance(); self::$instance = self::getInstance();
@ -105,7 +104,7 @@ class MachineDetails
/** /**
* @return string|null * @return string|null
*/ */
public static function region() public static function region(): ?string
{ {
if(self::$instance === null) if(self::$instance === null)
self::$instance = self::getInstance(); self::$instance = self::getInstance();
@ -116,19 +115,16 @@ class MachineDetails
/** /**
* @return string|null * @return string|null
*/ */
public static function publicIp() public static function publicIp(): ?string
{ {
if(self::$instance === null) if(self::$instance === null)
self::$instance = self::getInstance(); self::$instance = self::getInstance();
if(self::$details['publicIp'] === null) { if(self::$details['publicIp'] === null) {
switch(self::$details['type']) { self::$details['publicIp'] = match (self::$details['type']) {
case 'ec2' : 'ec2' => self::getEc2PublicIp(),
self::$details['publicIp'] = self::getEc2PublicIp(); default => self::getLocalPublicIp(),
break; };
default :
self::$details['publicIp'] = self::getLocalPublicIp();
}
} }
return self::$details['privateIp']; return self::$details['privateIp'];
@ -137,7 +133,7 @@ class MachineDetails
/** /**
* @return string|null * @return string|null
*/ */
public static function privateIp() public static function privateIp(): ?string
{ {
if(self::$instance === null) if(self::$instance === null)
self::$instance = self::getInstance(); self::$instance = self::getInstance();
@ -147,12 +143,12 @@ class MachineDetails
/* Private methods */ /* Private methods */
private static function getLocalPublicIp() private static function getLocalPublicIp(): string
{ {
return '127.0.0.1'; return '127.0.0.1';
} }
private static function getEc2PublicIp() private static function getEc2PublicIp(): false|string
{ {
if(self::$instance === null) if(self::$instance === null)
self::$instance = self::getInstance(); self::$instance = self::getInstance();
@ -186,7 +182,7 @@ class MachineDetails
*/ */
private function __clone() {} private function __clone() {}
private function determineMachineType() private function determineMachineType(): string
{ {
$this->shortenTimeout(); $this->shortenTimeout();
$hostname = @file_get_contents('http://169.254.169.254/latest/meta-data/hostname'); $hostname = @file_get_contents('http://169.254.169.254/latest/meta-data/hostname');
@ -199,7 +195,7 @@ class MachineDetails
} }
} }
private function getLocalData() private function getLocalData(): array
{ {
return [ return [
'id' => 'dev', 'id' => 'dev',
@ -210,7 +206,7 @@ class MachineDetails
]; ];
} }
private function getEc2Data() private function getEc2Data(): array
{ {
/* /*
* curl "http://169.254.169.254/latest/dynamic/instance-identity/document" * curl "http://169.254.169.254/latest/dynamic/instance-identity/document"
@ -253,7 +249,7 @@ class MachineDetails
return $out; return $out;
} }
private function shortenTimeout() private function shortenTimeout(): void
{ {
if($this->socketTimeout === null) { if($this->socketTimeout === null) {
$this->socketTimeout = ini_get('default_socket_timeout'); $this->socketTimeout = ini_get('default_socket_timeout');
@ -262,7 +258,7 @@ class MachineDetails
ini_set('default_socket_timeout', 2); ini_set('default_socket_timeout', 2);
} }
private function resetTimeout() private function resetTimeout(): void
{ {
if($this->socketTimeout !== null) { if($this->socketTimeout !== null) {
ini_set('default_socket_timeout', $this->socketTimeout); ini_set('default_socket_timeout', $this->socketTimeout);

View File

@ -3,7 +3,6 @@
* Global helper functions * Global helper functions
* *
* @copyright (c) 2018, Fairbanks Publishing * @copyright (c) 2018, Fairbanks Publishing
* @license Proprietary
*/ */
if(!function_exists('array_combine_safe')) { if(!function_exists('array_combine_safe')) {
@ -16,7 +15,7 @@ if(!function_exists('array_combine_safe')) {
* *
* @return array * @return array
*/ */
function array_combine_safe(array $keys = [], array $values = [], $default = null) function array_combine_safe(array $keys = [], array $values = [], $default = null): array
{ {
if (empty($keys)) { if (empty($keys)) {
return []; return [];
@ -43,7 +42,7 @@ if(!function_exists('array_limit_keys')) {
* *
* @return array * @return array
*/ */
function array_limit_keys(array $keys = [], array $input = []) function array_limit_keys(array $keys = [], array $input = []): array
{ {
if(empty($keys)) { if(empty($keys)) {
return []; return [];
@ -99,7 +98,7 @@ if(!function_exists('boolean')) {
* *
* @return boolean * @return boolean
*/ */
function boolean($var) function boolean(bool|int|string|null $var): bool
{ {
if (is_bool($var)) { if (is_bool($var)) {
return ($var == true); return ($var == true);
@ -108,16 +107,10 @@ if(!function_exists('boolean')) {
if (is_string($var)) { if (is_string($var)) {
$var = strtolower($var); $var = strtolower($var);
switch($var) { return match ($var) {
case 'true' : 'true', 'on', 'yes', 'y', '1' => true,
case 'on' : default => false,
case 'yes' : };
case 'y' :
case '1' :
return true;
default :
return false;
}
} }
if (is_numeric($var)) { if (is_numeric($var)) {
@ -131,10 +124,10 @@ if(!function_exists('boolean')) {
if(!function_exists('config')) { if(!function_exists('config')) {
/** /**
* @param string $key * @param string $key
* @param scalar $default * @param float|bool|int|string|null $default
* @return scalar * @return float|bool|int|string|null
*/ */
function config($key, $default = null) function config(string $key, float|bool|int|string $default = null): float|bool|int|string|null
{ {
if (array_key_exists($key, $_ENV)) { if (array_key_exists($key, $_ENV)) {
return $_ENV[$key]; return $_ENV[$key];
@ -149,7 +142,7 @@ if(!function_exists('app_echo')) {
* @param string $message * @param string $message
* @param array $context * @param array $context
*/ */
function app_echo($message, $context = []) function app_echo(string $message, array $context = []): void
{ {
if (is_array($context) && !empty($context)) { if (is_array($context) && !empty($context)) {
$message .= ' ' . json_encode($context); $message .= ' ' . json_encode($context);

View File

@ -1,9 +1,10 @@
{ {
"require": { "require": {
"php": "^8.2",
"ext-json": "*", "ext-json": "*",
"aws/aws-sdk-php": "^3.173", "aws/aws-sdk-php": "^3.209",
"nesbot/carbon": "^2.45", "nesbot/carbon": "^2.68",
"vlucas/phpdotenv": "^5.3" "vlucas/phpdotenv": "^5.5"
}, },
"config": { "config": {
"optimize-autoloader": true, "optimize-autoloader": true,