backup_path = null; $this->origin_dbname = null; } /* (2) Initializes a directory * * @db_name The database name * * @return outName outDesc * --------------------------------------------------------*/ private function initDir(string $db_name){ /* (1) Manage 'BACKUP' root directory ---------------------------------------------------------*/ /* (1) If not exists -> try to create it */ if( !is_dir(__BACKUP__) ) mkdir(__BACKUP__); /* (2) Try to override permissions */ chmod(__BACKUP__, 0775); /* (2) Manage sub-directory ---------------------------------------------------------*/ /* (1) If @db_name is 'preview_@database_hash' -> extract @database */ if( preg_match('/^preview_(\w+)_[a-f0-9]+$/', $db_name, $m) ) $db_name = $m[1]; /* (2) Store @db_name as origin */ $this->origin_dbname = $db_name; /* (3) Store backup path */ $this->backup_path =__BACKUP__."/$db_name"; /* (4) If dir. already exists -> do nothing more */ if( is_dir($this->backup_path) ) return; /* (4) Else -> try to create + set permissions */ mkdir($this->backup_path); chmod($this->backup_path, 0775); } /* (3) Scan directory files * * @path Directory path * * @return files Array containing file names * ---------------------------------------------------------*/ private function scandir(string $path) : array { /* (1) Return [] if not a directory */ if( !is_dir($path) ) return []; /* (2) Scan the directory */ $files = scandir($path); /* (3) Remove '.' and '..' (2 first elements) */ $files = array_slice($files, 2); /* (4) Return file list */ return $files; } /* (4) List available versions for this department * * @return versions Version list * ---------------------------------------------------------*/ public function get($args){ /* (1) Initialize directory for current database (department) */ $this->initDir( $_SESSION['CurrentDatabase'] ); /* (2) Strip extensions */ $versions = array_map( function($e){ return pathinfo($e, PATHINFO_FILENAME); }, $this->scandir($this->backup_path) ); /* (3) Return versions */ return ['versions' => $versions ]; } /* (5) Remove an existing version for this department * * @version Version name (typically snapshot date) * * @return deleted Whether the version has been deleted * ---------------------------------------------------------*/ public function delete($args){ $version = null; extract($args); /* (1) Initialize directory for current database (department) */ $this->initDir( $_SESSION['CurrentDatabase'] ); /* (2) Dispatch 'unlink' result */ return [ 'deleted' => unlink($this->backup_path."/$version.sql") ]; } /* (6) Creates a new version (snapshot of database) from now * * @return created_id The created version id (date) * ---------------------------------------------------------*/ public function post($args){ /* (1) Initialize directory for current database (department) */ $this->initDir( $_SESSION['CurrentDatabase'] ); /* (2) Try to create the snapshot */ try{ /* (2.1) Get database configuration */ $conf = Repo::getDBConfig(); /* (2.2) Try to dump the database */ $dump = new Mysqldump( 'mysql:host='.$conf['host'].';dbname='.$conf['dbname'], $conf['username'], $conf['password'], [ "compress" => Mysqldump::GZIP ] ); /* (2.3) Get current date (for naming the version) */ $current_date = date('d-m-Y'); /* (2.4) Store the version */ $dump->start($this->backup_path."/$current_date.sql"); /* (2.5) Return status */ return ['created_id' => $current_date ]; /* (3) On error -> dispatch error */ }catch(\Exception $e){ return ['error' => new Error(Err::RepoError)]; } } /* (6) ( Switches to preview || Applies on prod ) for a version * * @apply If 0 -> preview version * If 1 -> apply version into prod database * @version [OPT] Version name to use (if ommited, switch back to prod database) * * @return created_id The created version id (date) * ---------------------------------------------------------*/ public function put($args){ $apply = null; $version = null; extract($args); /* (1) Initialisation ---------------------------------------------------------*/ /* (1) Initialize directory for current database (department) */ $this->initDir( $_SESSION['CurrentDatabase'] ); /* (2) Get department repository */ /** @var department $dept_repo */ $dept_repo = Repo::getRepo('department'); /* (3) Check whether we have to [apply OR preview] */ $apply = ( $apply === '1' ); /* (2) If back to 'prod' database ---------------------------------------------------------*/ if( is_null($version) ){ /* (1) Reset database to 'prod' */ $_SESSION['CurrentDatabase'] = $this->origin_dbname; $_SESSION['VERSION'] = null; /* (2) Return success */ return [ 'updated' => true ]; } /* (3) Read the backup version ---------------------------------------------------------*/ /* (1) Start buffer */ ob_start(); /* (2) Read backup file */ readgzfile($this->backup_path."/$version.sql"); /* (3) Store & Flush buffer into variable */ $snapshot = ob_get_clean(); /* (4) Manage error */ if( strlen($snapshot) === 0 ) return ['error' => new Error(Err::RepoError)]; /* (4) APPLY into 'prod' database ---------------------------------------------------------*/ if( $apply ){ /* (1) Restore from this version */ $restored = $dept_repo->restore($this->origin_dbname, $snapshot); $_SESSION['VERSION'] = null; /* (2) Dispatch repo execution status */ return [ 'updated' => $restored ]; } /* (5) PREVIEW version database ---------------------------------------------------------*/ /* (1) Try to get 'preview' database name */ $preview_dbname = $dept_repo->previewExists($this->origin_dbname, $version); /* (2) If does not exist -> create it */ if( is_null($preview_dbname) ){ /* 1. Try to create preview */ $preview_dbname = $dept_repo->createPreview($this->origin_dbname, $version); /* 2. Switch to preview */ $dept_repo->restore($preview_dbname, $snapshot); } /* (3) Store 'preview' database in session */ $_SESSION['CurrentDatabase'] = $preview_dbname; $_SESSION['VERSION'] = $version; /* (4) Return status */ return [ 'updated' => true ]; } }