added version handling
This commit is contained in:
parent
176bd9dc83
commit
4f52e99a92
|
@ -1,8 +1,8 @@
|
|||
{
|
||||
"name": "24unix/bindapi",
|
||||
"description": "manage Bind9 DNS server via REST API",
|
||||
"version": "2023.0.1",
|
||||
"build_number": "344",
|
||||
"version": "1.0.7",
|
||||
"build_number": "345",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Micha Espey",
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
|
||||
use Phinx\Db\Adapter\MysqlAdapter;
|
||||
|
||||
class ApiKeyCreationDate extends Phinx\Migration\AbstractMigration
|
||||
{
|
||||
public function change()
|
||||
{
|
||||
$this->table('apikeys', [
|
||||
'id' => false,
|
||||
'primary_key' => ['id'],
|
||||
'engine' => 'InnoDB',
|
||||
'encoding' => 'utf8mb4',
|
||||
'collation' => 'utf8mb4_unicode_ci',
|
||||
'comment' => '',
|
||||
'row_format' => 'DYNAMIC',
|
||||
])
|
||||
->addColumn('created_at', 'timestamp', [
|
||||
'null' => false,
|
||||
'after' => 'apikey',
|
||||
])
|
||||
->save();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
|
||||
use Phinx\Db\Adapter\MysqlAdapter;
|
||||
|
||||
class UniqueConfigValues extends Phinx\Migration\AbstractMigration
|
||||
{
|
||||
public function change()
|
||||
{
|
||||
$this->table('config', [
|
||||
'id' => false,
|
||||
'primary_key' => ['name'],
|
||||
'engine' => 'InnoDB',
|
||||
'encoding' => 'utf8mb4',
|
||||
'collation' => 'utf8mb4_general_ci',
|
||||
'comment' => '',
|
||||
'row_format' => 'DYNAMIC',
|
||||
])
|
||||
->addIndex(['name'], [
|
||||
'name' => 'name',
|
||||
'unique' => true,
|
||||
])
|
||||
->save();
|
||||
}
|
||||
}
|
|
@ -129,7 +129,7 @@ return array (
|
|||
'CHARACTER_SET_NAME' => 'utf8mb4',
|
||||
'COLLATION_NAME' => 'utf8mb4_general_ci',
|
||||
'COLUMN_TYPE' => 'varchar(256)',
|
||||
'COLUMN_KEY' => '',
|
||||
'COLUMN_KEY' => 'PRI',
|
||||
'EXTRA' => '',
|
||||
'PRIVILEGES' => 'select,insert,update,references',
|
||||
'COLUMN_COMMENT' => '',
|
||||
|
@ -160,33 +160,27 @@ return array (
|
|||
'IS_GENERATED' => 'NEVER',
|
||||
'GENERATION_EXPRESSION' => NULL,
|
||||
),
|
||||
'fff' =>
|
||||
array (
|
||||
'TABLE_CATALOG' => 'def',
|
||||
'TABLE_NAME' => 'config',
|
||||
'COLUMN_NAME' => 'fff',
|
||||
'ORDINAL_POSITION' => 3,
|
||||
'COLUMN_DEFAULT' => NULL,
|
||||
'IS_NULLABLE' => 'NO',
|
||||
'DATA_TYPE' => 'int',
|
||||
'CHARACTER_MAXIMUM_LENGTH' => NULL,
|
||||
'CHARACTER_OCTET_LENGTH' => NULL,
|
||||
'NUMERIC_PRECISION' => 10,
|
||||
'NUMERIC_SCALE' => 0,
|
||||
'DATETIME_PRECISION' => NULL,
|
||||
'CHARACTER_SET_NAME' => NULL,
|
||||
'COLLATION_NAME' => NULL,
|
||||
'COLUMN_TYPE' => 'int(11)',
|
||||
'COLUMN_KEY' => '',
|
||||
'EXTRA' => '',
|
||||
'PRIVILEGES' => 'select,insert,update,references',
|
||||
'COLUMN_COMMENT' => '',
|
||||
'IS_GENERATED' => 'NEVER',
|
||||
'GENERATION_EXPRESSION' => NULL,
|
||||
),
|
||||
),
|
||||
'indexes' =>
|
||||
array (
|
||||
'name' =>
|
||||
array (
|
||||
1 =>
|
||||
array (
|
||||
'Table' => 'config',
|
||||
'Non_unique' => 0,
|
||||
'Key_name' => 'name',
|
||||
'Seq_in_index' => 1,
|
||||
'Column_name' => 'name',
|
||||
'Collation' => 'A',
|
||||
'Sub_part' => NULL,
|
||||
'Packed' => NULL,
|
||||
'Null' => '',
|
||||
'Index_type' => 'BTREE',
|
||||
'Comment' => '',
|
||||
'Index_comment' => '',
|
||||
),
|
||||
),
|
||||
),
|
||||
'foreign_keys' => NULL,
|
||||
),
|
||||
|
@ -927,6 +921,30 @@ return array (
|
|||
'IS_GENERATED' => 'NEVER',
|
||||
'GENERATION_EXPRESSION' => NULL,
|
||||
),
|
||||
'created_at' =>
|
||||
array (
|
||||
'TABLE_CATALOG' => 'def',
|
||||
'TABLE_NAME' => 'apikeys',
|
||||
'COLUMN_NAME' => 'created_at',
|
||||
'ORDINAL_POSITION' => 5,
|
||||
'COLUMN_DEFAULT' => NULL,
|
||||
'IS_NULLABLE' => 'NO',
|
||||
'DATA_TYPE' => 'timestamp',
|
||||
'CHARACTER_MAXIMUM_LENGTH' => NULL,
|
||||
'CHARACTER_OCTET_LENGTH' => NULL,
|
||||
'NUMERIC_PRECISION' => NULL,
|
||||
'NUMERIC_SCALE' => NULL,
|
||||
'DATETIME_PRECISION' => 0,
|
||||
'CHARACTER_SET_NAME' => NULL,
|
||||
'COLLATION_NAME' => NULL,
|
||||
'COLUMN_TYPE' => 'timestamp',
|
||||
'COLUMN_KEY' => '',
|
||||
'EXTRA' => '',
|
||||
'PRIVILEGES' => 'select,insert,update,references',
|
||||
'COLUMN_COMMENT' => '',
|
||||
'IS_GENERATED' => 'NEVER',
|
||||
'GENERATION_EXPRESSION' => NULL,
|
||||
),
|
||||
),
|
||||
'indexes' =>
|
||||
array (
|
||||
|
|
|
@ -26,6 +26,7 @@ use App\Repository\DomainRepository;
|
|||
use App\Repository\DynDNSRepository;
|
||||
use App\Repository\NameserverRepository;
|
||||
use App\Repository\PanelRepository;
|
||||
use App\Repository\SettingsRepository;
|
||||
use Arubacao\TldChecker\Validator;
|
||||
use Exception;
|
||||
use JsonMapper;
|
||||
|
@ -62,11 +63,38 @@ class CLIController
|
|||
private readonly PanelRepository $panelRepository,
|
||||
private readonly ConfigController $configController,
|
||||
private readonly EncryptionController $encryptionController,
|
||||
private readonly SettingsRepository $settingsRepository,
|
||||
private $logger,
|
||||
private bool $quiet
|
||||
)
|
||||
{
|
||||
$this->commandGroupContainer = (new CommandGroupContainer())
|
||||
->addCommandGroup(commandGroup: (new CommandGroup(name: 'apikeys', description: 'API keys to access this bindAPI'))
|
||||
->addCommand(command: new Command(
|
||||
name: 'list',
|
||||
callback: function () {
|
||||
$this->apikeysList();
|
||||
}))
|
||||
->addCommand(command: new Command(
|
||||
name: 'create',
|
||||
callback: function () {
|
||||
$this->apikeysCreate();
|
||||
},
|
||||
mandatoryParameters: ['name']))
|
||||
->addCommand(command: new Command(
|
||||
name: 'update',
|
||||
callback: function () {
|
||||
$this->apikeysUpdate();
|
||||
},
|
||||
mandatoryParameters: ['ID',],
|
||||
optionalParameters: ['name=<name>']))
|
||||
->addCommand(command: new Command(
|
||||
name: 'delete',
|
||||
callback: function () {
|
||||
$this->apikeysDelete();
|
||||
},
|
||||
mandatoryParameters: ['ID'])))
|
||||
|
||||
->addCommandGroup(commandGroup: (new CommandGroup(name: 'check', description: 'health checks the system can perform'))
|
||||
->addCommand(command: new Command(
|
||||
name: 'permissions',
|
||||
|
@ -118,9 +146,9 @@ class CLIController
|
|||
->addCommand(command: new Command(
|
||||
name: 'version',
|
||||
callback: function () {
|
||||
$this->checksVersion();
|
||||
$this->checkVersion();
|
||||
},
|
||||
optionalParameters: ['major:minor:patch'],
|
||||
optionalParameters: ['update'],
|
||||
description: 'Read or set the bindApi version in the database')))
|
||||
->addCommandGroup(commandGroup: (new CommandGroup(name: 'panels', description: 'all KeyHelp systems configured'))
|
||||
->addCommand(command: new Command(
|
||||
|
@ -227,31 +255,6 @@ class CLIController
|
|||
$this->dynDnsDelete();
|
||||
},
|
||||
mandatoryParameters: ['ID'])))
|
||||
->addCommandGroup(commandGroup: (new CommandGroup(name: 'apikeys', description: 'API keys to access this bindAPI'))
|
||||
->addCommand(command: new Command(
|
||||
name: 'list',
|
||||
callback: function () {
|
||||
$this->apikeysList();
|
||||
}))
|
||||
->addCommand(command: new Command(
|
||||
name: 'create',
|
||||
callback: function () {
|
||||
$this->apikeysCreate();
|
||||
},
|
||||
mandatoryParameters: ['name']))
|
||||
->addCommand(command: new Command(
|
||||
name: 'update',
|
||||
callback: function () {
|
||||
$this->apikeysUpdate();
|
||||
},
|
||||
mandatoryParameters: ['ID',],
|
||||
optionalParameters: ['name=<name>']))
|
||||
->addCommand(command: new Command(
|
||||
name: 'delete',
|
||||
callback: function () {
|
||||
$this->apikeysDelete();
|
||||
},
|
||||
mandatoryParameters: ['ID'])))
|
||||
->addCommandGroup(commandGroup: (new CommandGroup(name: 'migrations', description: 'maintain database migrations'))
|
||||
->addCommand(command: new Command(
|
||||
name: 'status',
|
||||
|
@ -1155,21 +1158,18 @@ class CLIController
|
|||
exit(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
function apikeysList(): void
|
||||
{
|
||||
$keys = $this->apikeyRepository->findAll();
|
||||
if (!empty($keys)) {
|
||||
echo 'All valid API keys:' . PHP_EOL;
|
||||
$table = new ConsoleTable();
|
||||
$table->setHeaders(content: ['ID', 'Name', 'API key prefix']);
|
||||
$table->setHeaders(content: ['ID', 'Name', 'API key prefix', 'Created at']);
|
||||
foreach ($keys as $key) {
|
||||
$row = [];
|
||||
$row[] = $key->getID();
|
||||
$row[] = $key->getName();
|
||||
$row[] = $key->getApikeyPrefix();
|
||||
$row[] = $key->getCreatedAt();
|
||||
$table->addRow(data: $row);
|
||||
}
|
||||
$table->setPadding(value: 2);
|
||||
|
@ -2002,9 +2002,49 @@ class CLIController
|
|||
echo 'Not yet implemented.' . PHP_EOL;
|
||||
}
|
||||
|
||||
private function checksVersion(): void
|
||||
private function checkVersion(): void
|
||||
{
|
||||
echo 'Not yet implemented.' . PHP_EOL;
|
||||
$update = false;
|
||||
if (isset($this->arguments[1])) {
|
||||
$action = $this->arguments[1];
|
||||
if ($action !== 'update') {
|
||||
if (!$this->quiet) {
|
||||
echo 'The only allowed argument is "' . COLOR_YELLOW . 'update' . COLOR_DEFAULT . '.' . PHP_EOL;
|
||||
}
|
||||
exit(1);
|
||||
}
|
||||
$update = true;
|
||||
}
|
||||
|
||||
$composerFile = dirname(path: __DIR__, levels: 2) . DIRECTORY_SEPARATOR . 'composer.json';
|
||||
$composerJson = json_decode(json: file_get_contents(filename: $composerFile), associative: false);
|
||||
|
||||
$fileVersion = $composerJson->version;
|
||||
$fileBuildNumber = $composerJson->build_number;
|
||||
[$major, $minor, $patch] = explode(separator: '.', string: $fileVersion);
|
||||
$version = [
|
||||
'major' => $major,
|
||||
'minor' => $minor,
|
||||
'patch' => $patch
|
||||
];
|
||||
$json = json_encode(value: ['version' => $version]);
|
||||
|
||||
echo "File version:\t\t$fileVersion" . PHP_EOL;
|
||||
echo "File build number:\t$fileBuildNumber" . PHP_EOL;
|
||||
|
||||
if ($update) {
|
||||
$this->settingsRepository->set(name: 'version', value: $json);
|
||||
$this->settingsRepository->set(name: 'buildnumber', value: $fileBuildNumber);
|
||||
}
|
||||
$currentDBVersion = $this->settingsRepository->findByName(name: 'version');
|
||||
$dbVersion = json_decode($currentDBVersion);
|
||||
|
||||
$currentDBBuildnumber= $this->settingsRepository->findByName(name: 'buildnumber');
|
||||
echo "DB version:\t\t";
|
||||
echo $dbVersion->version->major . '.';
|
||||
echo $dbVersion->version->minor . '.';
|
||||
echo $dbVersion->version->patch . PHP_EOL;
|
||||
echo "DB build number:\t$currentDBBuildnumber" . PHP_EOL;
|
||||
}
|
||||
|
||||
private function dynDnyUpdate(): void
|
||||
|
|
|
@ -2,9 +2,6 @@
|
|||
|
||||
namespace App\Controller;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class ConfigController
|
||||
{
|
||||
private array $config;
|
||||
|
|
|
@ -5,20 +5,16 @@ namespace App\Entity;
|
|||
use App\Controller\ConfigController;
|
||||
use App\Controller\EncryptionController;
|
||||
use Exception;
|
||||
use SodiumException;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class Apikey
|
||||
{
|
||||
|
||||
public function __construct(
|
||||
private int $id = 0,
|
||||
private string $name = '',
|
||||
private string $apikey = '',
|
||||
private string $apikeyPrefix = '',
|
||||
private readonly string $passphrase = ''
|
||||
private readonly string $passphrase = '',
|
||||
private string $createdAt = ''
|
||||
)
|
||||
{
|
||||
if ($this->passphrase) {
|
||||
|
@ -31,82 +27,45 @@ class Apikey
|
|||
|
||||
try {
|
||||
$this->apikey = $encryptionController->safeEncrypt(message: $this->passphrase, key: $encryptionKey);
|
||||
} catch (Exception|SodiumException $e) {
|
||||
} catch (Exception $e) {
|
||||
exit($e->getMessage() . PHP_EOL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getPassphrase(): string
|
||||
public function getCreatedAt(): string
|
||||
{
|
||||
return $this->passphrase;
|
||||
return $this->createdAt;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return String
|
||||
*/
|
||||
public function getApikey(): string
|
||||
{
|
||||
return $this->apikey;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getApikeyPrefix(): string
|
||||
{
|
||||
return $this->apikeyPrefix;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getId(): int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $id
|
||||
*/
|
||||
public function setId(int $id): void
|
||||
{
|
||||
$this->id = $id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return String
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $apikeyPrefix
|
||||
*/
|
||||
public function setApikeyPrefix(string $apikeyPrefix): void
|
||||
{
|
||||
$this->apikeyPrefix = $apikeyPrefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param String $apiToken
|
||||
*/
|
||||
public function setApikey(string $apikey): void
|
||||
{
|
||||
$this->apikey = $apikey;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param String $name
|
||||
*/
|
||||
public function setName(string $name): void
|
||||
{
|
||||
$this->name = $name;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
|
||||
namespace App\Controller;
|
||||
namespace App\Provider;
|
||||
|
||||
//error_reporting(error_level: E_ALL);
|
||||
|
||||
|
@ -8,6 +8,7 @@ namespace App\Controller;
|
|||
use PDO;
|
||||
use PDOException;
|
||||
use PHPUnit\Exception;
|
||||
use App\Controller\ConfigController;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -22,6 +23,7 @@ class DatabaseConnection
|
|||
const TABLE_PANELS = self::TABLE_PREFIX . "panels";
|
||||
const TABLE_APIKEYS = self::TABLE_PREFIX . "apikeys";
|
||||
const TABLE_DYNDNS = self::TABLE_PREFIX . "dyndns";
|
||||
const TABLE_SETTINGS = self::TABLE_PREFIX . 'config';
|
||||
|
||||
public function __construct(private readonly ConfigController $configController)
|
||||
{
|
|
@ -3,7 +3,7 @@ namespace App\Repository;
|
|||
|
||||
error_reporting(error_level: E_ALL);
|
||||
|
||||
use App\Controller\DatabaseConnection;
|
||||
use App\Provider\DatabaseConnection;
|
||||
use App\Controller\EncryptionController;
|
||||
use App\Entity\Apikey;
|
||||
use PDO;
|
||||
|
@ -18,27 +18,24 @@ class ApikeyRepository
|
|||
{}
|
||||
|
||||
|
||||
/**
|
||||
* @return array|false
|
||||
*/
|
||||
public function findAll(): bool|array
|
||||
{
|
||||
|
||||
$sql = "
|
||||
SELECT id, name, apikey_prefix, apikey
|
||||
SELECT id, name, apikey_prefix, apikey, created_at
|
||||
FROM " . DatabaseConnection::TABLE_APIKEYS;
|
||||
|
||||
try {
|
||||
$statement = $this->databaseConnection->getConnection()->prepare(query: $sql);
|
||||
$statement->execute();
|
||||
|
||||
$apikeys = [];
|
||||
$apiKeys = [];
|
||||
|
||||
while ($result = $statement->fetch()) {
|
||||
$apikey = new Apikey(id: $result['id'], name: $result['name'], apikey: $result['apikey'], apikeyPrefix: $result['apikey_prefix']);
|
||||
$apikeys[] = $apikey;
|
||||
$apikey = new Apikey(id: $result['id'], name: $result['name'], apikey: $result['apikey'], apikeyPrefix: $result['apikey_prefix'], createdAt: $result['created_at']);
|
||||
$apiKeys[] = $apikey;
|
||||
}
|
||||
return $apikeys;
|
||||
return $apiKeys;
|
||||
} catch (PDOException $e) {
|
||||
exit($e->getMessage());
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
namespace App\Repository;
|
||||
|
||||
use App\Controller\ConfigController;
|
||||
use App\Controller\DatabaseConnection;
|
||||
use App\Provider\DatabaseConnection;
|
||||
use App\Entity\Domain;
|
||||
use Monolog\Logger;
|
||||
use PDO;
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
namespace App\Repository;
|
||||
|
||||
use App\Controller\DatabaseConnection;
|
||||
use App\Provider\DatabaseConnection;
|
||||
use App\Entity\DynDNS;
|
||||
use Monolog\Logger;
|
||||
use PDO;
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
namespace App\Repository;
|
||||
|
||||
use App\Controller\DatabaseConnection;
|
||||
use App\Provider\DatabaseConnection;
|
||||
use App\Entity\Nameserver;
|
||||
use PDO;
|
||||
use PDOException;
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
namespace App\Repository;
|
||||
|
||||
use App\Controller\DatabaseConnection;
|
||||
use App\Provider\DatabaseConnection;
|
||||
use App\Entity\Panel;
|
||||
use PDO;
|
||||
use PDOException;
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
<?php declare(strict_types=1);
|
||||
namespace App\Repository;
|
||||
|
||||
error_reporting(error_level: E_ALL);
|
||||
|
||||
use App\Provider\DatabaseConnection;
|
||||
use App\Controller\EncryptionController;
|
||||
use PDO;
|
||||
use PDOException;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
readonly class SettingsRepository
|
||||
{
|
||||
public function __construct(private DatabaseConnection $databaseConnection, EncryptionController $encryptionController)
|
||||
{}
|
||||
|
||||
public function findByName(string $name): string|bool
|
||||
{
|
||||
$sql = "
|
||||
SELECT value
|
||||
FROM " . DatabaseConnection::TABLE_SETTINGS . "
|
||||
WHERE name = :name;
|
||||
";
|
||||
|
||||
try {
|
||||
$statement = $this->databaseConnection->getConnection()->prepare(query: $sql);
|
||||
$statement->bindParam(param: ':name', var: $name);
|
||||
$statement->execute();
|
||||
if ($result = $statement->fetch(mode: PDO::FETCH_ASSOC)) {
|
||||
return $result['value'];
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} catch (PDOException $e) {
|
||||
exit($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function set(string $name, string $value): int
|
||||
{
|
||||
|
||||
$sql = "
|
||||
INSERT INTO " . DatabaseConnection::TABLE_SETTINGS . " (name, value)
|
||||
VALUES (:name, :value)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
value = :value
|
||||
";
|
||||
|
||||
try {
|
||||
$statement = $this->databaseConnection->getConnection()->prepare(query: $sql);
|
||||
$statement->bindParam(param: ':name', var: $name);
|
||||
$statement->bindParam(param: ':value', var: $value);
|
||||
|
||||
$statement->execute();
|
||||
return intval(value: $this->databaseConnection->getConnection()->lastInsertId());
|
||||
} catch (PDOException $e) {
|
||||
exit($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,9 +1,13 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Controller;
|
||||
namespace App\Service;
|
||||
|
||||
error_reporting(error_level: E_ALL);
|
||||
|
||||
use App\Controller\ConfigController;
|
||||
use App\Controller\CLIController;
|
||||
use App\Controller\DomainController;
|
||||
use App\Controller\RequestController;
|
||||
use App\Repository\DomainRepository;
|
||||
use App\Repository\DynDNSRepository;
|
||||
use DI\Container;
|
||||
|
@ -17,9 +21,6 @@ use Monolog\Level;
|
|||
use Monolog\Logger;
|
||||
use function DI\autowire;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class BindAPI
|
||||
{
|
||||
private Logger $logger;
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
|
||||
use App\Controller\BindAPI;
|
||||
use App\Service\BindAPI;
|
||||
|
||||
error_reporting(error_level: E_ALL & ~E_DEPRECATED);
|
||||
|
||||
|
|
Loading…
Reference in New Issue