Ivan - Add Database Backup, FileDownloader, FileUploader and LinearCongruentialGenerator classes [skip ci]
This commit is contained in:
parent
be49990091
commit
134540fed9
|
@ -4,7 +4,8 @@
|
||||||
"respect/validation": "^1.1",
|
"respect/validation": "^1.1",
|
||||||
"phpmailer/phpmailer": "^5.2",
|
"phpmailer/phpmailer": "^5.2",
|
||||||
"google/recaptcha": "~1.1",
|
"google/recaptcha": "~1.1",
|
||||||
"gabordemooij/redbean": "^4.3"
|
"gabordemooij/redbean": "^4.3",
|
||||||
|
"ifsnop/mysqldump-php": "2.*"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"phpunit/phpunit": "5.0.*"
|
"phpunit/phpunit": "5.0.*"
|
||||||
|
|
|
@ -9,6 +9,8 @@ require_once 'system/get-logs.php';
|
||||||
require_once 'system/get-mail-templates.php';
|
require_once 'system/get-mail-templates.php';
|
||||||
require_once 'system/edit-mail-template.php';
|
require_once 'system/edit-mail-template.php';
|
||||||
require_once 'system/recover-mail-template.php';
|
require_once 'system/recover-mail-template.php';
|
||||||
|
require_once 'system/backup-database.php';
|
||||||
|
require_once 'system/download.php';
|
||||||
|
|
||||||
$systemControllerGroup = new ControllerGroup();
|
$systemControllerGroup = new ControllerGroup();
|
||||||
$systemControllerGroup->setGroupPath('/system');
|
$systemControllerGroup->setGroupPath('/system');
|
||||||
|
@ -23,5 +25,7 @@ $systemControllerGroup->addController(new GetLogsController);
|
||||||
$systemControllerGroup->addController(new GetMailTemplatesController);
|
$systemControllerGroup->addController(new GetMailTemplatesController);
|
||||||
$systemControllerGroup->addController(new EditMailTemplateController);
|
$systemControllerGroup->addController(new EditMailTemplateController);
|
||||||
$systemControllerGroup->addController(new RecoverMailTemplateController);
|
$systemControllerGroup->addController(new RecoverMailTemplateController);
|
||||||
|
$systemControllerGroup->addController(new BackupDatabaseController);
|
||||||
|
$systemControllerGroup->addController(new DownloadController);
|
||||||
|
|
||||||
$systemControllerGroup->finalize();
|
$systemControllerGroup->finalize();
|
|
@ -0,0 +1,30 @@
|
||||||
|
<?php
|
||||||
|
use Ifsnop\Mysqldump as IMysqldump;
|
||||||
|
|
||||||
|
class BackupDatabaseController extends Controller {
|
||||||
|
const PATH = '/backup-database';
|
||||||
|
|
||||||
|
public function validations() {
|
||||||
|
return [
|
||||||
|
'permission' => 'staff_3',
|
||||||
|
'requestData' => []
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handler() {
|
||||||
|
global $mysql_host;
|
||||||
|
global $mysql_database;
|
||||||
|
global $mysql_user;
|
||||||
|
global $mysql_password;
|
||||||
|
|
||||||
|
$fileDownloader = FileDownloader::getInstance();
|
||||||
|
$fileDownloader->setFileName('backup.sql');
|
||||||
|
|
||||||
|
$mysqlDump = new IMysqldump\Mysqldump('mysql:host='. $mysql_host .';dbname=' . $mysql_database, $mysql_user, $mysql_password);
|
||||||
|
$mysqlDump->start($fileDownloader->getFullFilePath());
|
||||||
|
|
||||||
|
if($fileDownloader->download()) {
|
||||||
|
$fileDownloader->eraseFile();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
<?php
|
||||||
|
use Ifsnop\Mysqldump as IMysqldump;
|
||||||
|
use Respect\Validation\Validator as DataValidator;
|
||||||
|
|
||||||
|
class DownloadController extends Controller {
|
||||||
|
const PATH = '/download';
|
||||||
|
|
||||||
|
public function validations() {
|
||||||
|
return [
|
||||||
|
'permission' => 'staff_1',
|
||||||
|
'requestData' => [
|
||||||
|
'file' => [
|
||||||
|
'validation' => DataValidator::alnum('_.')->noWhitespace()
|
||||||
|
]
|
||||||
|
]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handler() {
|
||||||
|
$fileDownloader = FileDownloader::getInstance();
|
||||||
|
$fileDownloader->setFileName(Controller::request('file'));
|
||||||
|
$fileDownloader->download();
|
||||||
|
}
|
||||||
|
}
|
|
@ -40,7 +40,10 @@ class InitSettingsController extends Controller {
|
||||||
'allow-attachments' => 0,
|
'allow-attachments' => 0,
|
||||||
'max-size' => 0,
|
'max-size' => 0,
|
||||||
'title' => 'Support Center',
|
'title' => 'Support Center',
|
||||||
'url' => 'http://www.opensupports.com/support'
|
'url' => 'http://www.opensupports.com/support',
|
||||||
|
'ticket-gap' => Hashing::generateRandomPrime(100000, 999999),
|
||||||
|
'file-gap' => Hashing::generateRandomPrime(100000, 999999),
|
||||||
|
'file-first-number' => Hashing::generateRandomNumber(100000, 999999),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -35,4 +35,5 @@ class ERRORS {
|
||||||
const INVALID_TEMPLATE = 'INVALID_TEMPLATE';
|
const INVALID_TEMPLATE = 'INVALID_TEMPLATE';
|
||||||
const INVALID_SUBJECT = 'INVALID_SUBJECT';
|
const INVALID_SUBJECT = 'INVALID_SUBJECT';
|
||||||
const INVALID_BODY = 'INVALID_BODY';
|
const INVALID_BODY = 'INVALID_BODY';
|
||||||
|
const INVALID_FILE = 'INVALID_FILE';
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,10 @@ include_once 'libs/Hashing.php';
|
||||||
include_once 'libs/MailSender.php';
|
include_once 'libs/MailSender.php';
|
||||||
include_once 'libs/Date.php';
|
include_once 'libs/Date.php';
|
||||||
include_once 'libs/DataStoreList.php';
|
include_once 'libs/DataStoreList.php';
|
||||||
|
include_once 'libs/LinearCongruentialGenerator.php';
|
||||||
|
include_once 'libs/FileManager.php';
|
||||||
|
include_once 'libs/FileDownloader.php';
|
||||||
|
include_once 'libs/FileUploader.php';
|
||||||
|
|
||||||
// LOAD DATA
|
// LOAD DATA
|
||||||
spl_autoload_register(function ($class) {
|
spl_autoload_register(function ($class) {
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
class FileDownloader extends FileManager {
|
||||||
|
|
||||||
|
private static $instance = null;
|
||||||
|
|
||||||
|
public static function getInstance() {
|
||||||
|
if (self::$instance === null) {
|
||||||
|
self::$instance = new FileDownloader();
|
||||||
|
}
|
||||||
|
|
||||||
|
return self::$instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function __construct() {}
|
||||||
|
|
||||||
|
public function download() {
|
||||||
|
$fullFilePath = $this->getFullFilePath();
|
||||||
|
|
||||||
|
if(file_exists($fullFilePath) && is_file($fullFilePath)) {
|
||||||
|
header('Cache-control: private');
|
||||||
|
header('Content-Type: application/octet-stream');
|
||||||
|
header('Content-Length: '.filesize($fullFilePath));
|
||||||
|
header('Content-Disposition: filename='. $this->getFileName());
|
||||||
|
|
||||||
|
flush();
|
||||||
|
$file = fopen($fullFilePath, 'r');
|
||||||
|
print fread($file, filesize($fullFilePath));
|
||||||
|
fclose($file);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function eraseFile() {
|
||||||
|
unlink($this->getLocalPath() . $this->getFileName());
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
abstract class FileManager {
|
||||||
|
private $fileName;
|
||||||
|
private $localPath = 'files/';
|
||||||
|
|
||||||
|
public function setLocalPath($localPath) {
|
||||||
|
$this->localPath = $localPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setFileName($fileName) {
|
||||||
|
$this->fileName = $fileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getLocalPath() {
|
||||||
|
return $this->localPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFileName() {
|
||||||
|
return $this->fileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFullFilePath() {
|
||||||
|
return $this->getLocalPath() . $this->getFileName();
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,10 @@
|
||||||
<?php
|
<?php
|
||||||
class FileUploader {
|
|
||||||
|
class FileUploader extends FileManager {
|
||||||
|
private $maxSize = 1024;
|
||||||
|
private $linearCongruentialGenerator;
|
||||||
|
private $linearCongruentialGeneratorOffset;
|
||||||
|
|
||||||
private static $instance = null;
|
private static $instance = null;
|
||||||
|
|
||||||
public static function getInstance() {
|
public static function getInstance() {
|
||||||
|
@ -12,7 +17,40 @@ class FileUploader {
|
||||||
|
|
||||||
private function __construct() {}
|
private function __construct() {}
|
||||||
|
|
||||||
public function upload() {
|
public function upload($file) {
|
||||||
// TODO: Implement file upload features
|
$newFileName = $this->generateNewName($file['name']);
|
||||||
|
|
||||||
|
if($file['size'] > (1024 * $this->maxSize)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
move_uploaded_file($file['tmp_name'], $this->getLocalPath() . $newFileName);
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function generateNewName($fileName) {
|
||||||
|
$newName = $fileName;
|
||||||
|
$newName = strtolower($newName);
|
||||||
|
$newName = preg_replace('/\s+/', '_', $newName);
|
||||||
|
|
||||||
|
if ($this->linearCongruentialGenerator instanceof LinearCongruentialGenerator) {
|
||||||
|
$newName = $this->linearCongruentialGenerator->generate($this->linearCongruentialGeneratorOffset) . '_' . $newName;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $newName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setGeneratorValues($gap, $first, $offset) {
|
||||||
|
$this->linearCongruentialGenerator = new LinearCongruentialGenerator();
|
||||||
|
$this->linearCongruentialGeneratorOffset = $offset;
|
||||||
|
|
||||||
|
$this->linearCongruentialGenerator->setGap($gap);
|
||||||
|
$this->linearCongruentialGenerator->setFirst($first);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setMaxSize($maxSize) {
|
||||||
|
$this->maxSize = $maxSize;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -7,10 +7,36 @@ class Hashing {
|
||||||
public static function verifyPassword($password, $hash) {
|
public static function verifyPassword($password, $hash) {
|
||||||
return password_verify($password, $hash);
|
return password_verify($password, $hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function generateRandomToken() {
|
public static function generateRandomToken() {
|
||||||
return md5(uniqid(rand()));
|
return md5(uniqid(rand()));
|
||||||
}
|
}
|
||||||
public static function getRandomTicketNumber($min,$max) {
|
|
||||||
return rand($min,$max);
|
public static function generateRandomNumber($min, $max) {
|
||||||
|
return rand($min, $max);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function generateRandomPrime($min, $max) {
|
||||||
|
$number = Hashing::generateRandomNumber($min, $max);
|
||||||
|
|
||||||
|
while(!Hashing::isPrime($number)) {
|
||||||
|
$number = Hashing::generateRandomNumber($min, $max);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $number;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function isPrime($number) {
|
||||||
|
$sqrt = sqrt($number);
|
||||||
|
$prime = true;
|
||||||
|
|
||||||
|
for($i = 0; $i < $sqrt; $i++) {
|
||||||
|
if($sqrt % 2 === 0) {
|
||||||
|
$prime = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $prime;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
<?php
|
||||||
|
class LinearCongruentialGenerator {
|
||||||
|
private $gap;
|
||||||
|
private $first;
|
||||||
|
private $min = 100000;
|
||||||
|
private $max = 999999;
|
||||||
|
|
||||||
|
public function setRange($min, $max) {
|
||||||
|
$this->min = $min;
|
||||||
|
$this->max = $max;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setGap($gap) {
|
||||||
|
if(!Hashing::isPrime($gap)) throw new Exception('LinearCongruentialGenerator: gap must be prime');
|
||||||
|
|
||||||
|
$this->gap = $gap;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setFirst($first) {
|
||||||
|
$this->first = $first;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function generate($offset) {
|
||||||
|
return ($this->first - $this->min + $offset * $this->gap) % ($this->max - $this->min + 1) + $this->min;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function generateFirst() {
|
||||||
|
return Hashing::generateRandomNumber($this->min, $this->max);
|
||||||
|
}
|
||||||
|
}
|
|
@ -46,17 +46,16 @@ class Ticket extends DataStore {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function generateUniqueTicketNumber() {
|
public function generateUniqueTicketNumber() {
|
||||||
|
$linearCongruentialGenerator = new LinearCongruentialGenerator();
|
||||||
$ticketQuantity = Ticket::count();
|
$ticketQuantity = Ticket::count();
|
||||||
$minValue = 100000;
|
|
||||||
$maxValue = 999999;
|
|
||||||
|
|
||||||
if ($ticketQuantity === 0) {
|
if ($ticketQuantity === 0) {
|
||||||
$ticketNumber = Hashing::getRandomTicketNumber($minValue, $maxValue);
|
$ticketNumber = $linearCongruentialGenerator->generateFirst();
|
||||||
} else {
|
} else {
|
||||||
$firstTicketNumber = Ticket::getTicket(1)->ticketNumber;
|
$linearCongruentialGenerator->setGap(Setting::getSetting('ticket-gap')->value);
|
||||||
$gap = 176611; //TODO: USE RANDOM PRIME INSTEAD
|
$linearCongruentialGenerator->setFirst(Ticket::getTicket(1)->ticketNumber);
|
||||||
|
|
||||||
$ticketNumber = ($firstTicketNumber - $minValue + $ticketQuantity * $gap) % ($maxValue - $minValue + 1) + $minValue;
|
$ticketNumber = $linearCongruentialGenerator->generate($ticketQuantity);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $ticketNumber;
|
return $ticketNumber;
|
||||||
|
|
|
@ -147,13 +147,15 @@ describe '/ticket/create' do
|
||||||
csrf_token: $csrf_token
|
csrf_token: $csrf_token
|
||||||
})
|
})
|
||||||
|
|
||||||
|
ticket_number_gap = $database.getRow('setting', 'ticket-gap', 'name')['value'].to_i
|
||||||
|
|
||||||
ticket0 = $database.getRow('ticket','Winter is coming','title')['ticket_number'].to_i
|
ticket0 = $database.getRow('ticket','Winter is coming','title')['ticket_number'].to_i
|
||||||
ticket1 = $database.getRow('ticket','Winter is coming1','title')['ticket_number'].to_i
|
ticket1 = $database.getRow('ticket','Winter is coming1','title')['ticket_number'].to_i
|
||||||
ticket2 = $database.getRow('ticket','Winter is coming2','title')['ticket_number'].to_i
|
ticket2 = $database.getRow('ticket','Winter is coming2','title')['ticket_number'].to_i
|
||||||
ticket3 = $database.getRow('ticket','Winter is coming3','title')['ticket_number'].to_i
|
ticket3 = $database.getRow('ticket','Winter is coming3','title')['ticket_number'].to_i
|
||||||
|
|
||||||
(ticket1).should.equal((ticket0 - 100000 + 1 * 176611) % 900000 + 100000)
|
(ticket1).should.equal((ticket0 - 100000 + 1 * ticket_number_gap) % 900000 + 100000)
|
||||||
(ticket2).should.equal((ticket0 - 100000 + 2 * 176611) % 900000 + 100000)
|
(ticket2).should.equal((ticket0 - 100000 + 2 * ticket_number_gap) % 900000 + 100000)
|
||||||
(ticket3).should.equal((ticket0 - 100000 + 3 * 176611) % 900000 + 100000)
|
(ticket3).should.equal((ticket0 - 100000 + 3 * ticket_number_gap) % 900000 + 100000)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue