Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- <?php
- if (!defined('BASEPATH')) {
- exit('No direct script access allowed');
- }
- /**
- *
- * NEOU CMS v4 CI Edition
- * @copyright (c) 2018, Alexander Fagard
- * @requires PHP version >= 5.6
- *
- * You cannot redistribute this document without written permission from the author
- *
- */
- use Cake\Filesystem\File;
- use Cake\Filesystem\Folder;
- class Core_update_model extends CI_Model {
- private $folders = array(
- 'application/controllers/' . CMS_DIR_NAME,
- 'application/helpers',
- 'application/language',
- 'application/libraries',
- 'application/models/backend',
- 'application/views/backend',
- 'application/core',
- 'application/third_party',
- 'application/hooks'
- );
- private $excluded_files = array(
- 'MY_Frontend.php',
- 'Config.php'
- );
- private $limit_files_per_open = true;
- // do not edit
- public $files_processed = 0;
- public $updates_folder;
- private $dir_unpack;
- private $max_files_per_open = 1024;
- private $current_file_count = 0;
- private $zip;
- private $manifest = array();
- private $manifest_file = 'MANIFEST.txt';
- private $identifier_file = 'SYSUPDATE.txt';
- public function __construct() {
- parent::__construct();
- $this->lang->load('core_update');
- $this->updates_folder = genpath(APPPATH . 'migrations/system_updates/');
- $this->dir_unpack = genpath();
- if (!extension_loaded('zip')) {
- show_error(sprintf($this->lang->line('update_zip_ext_failed_load'), __CLASS__), 500);
- } else {
- $this->zip = new \ZipArchive;
- }
- }
- /**
- * Restores version before update
- * Deletes new files that were added from the update
- *
- * @throws Exception
- * @return void
- */
- public function restore_previous() {
- try {
- $beforeupdate = $this->find_previous_version();
- $new_manifest_obj = new File($this->updates_folder . 'manifests/manifest_new.txt');
- $old_manifest_obj = new File($this->updates_folder . 'manifests/manifest_old.txt');
- $new_manifest = $new_manifest_obj->read();
- $old_manifest = $old_manifest_obj->read();
- if ($new_manifest === false || $old_manifest === false) {
- throw new Exception($this->lang->line('update_manifest_error'));
- }
- $new_manifest = unserialize($new_manifest);
- $old_manifest = unserialize($old_manifest);
- $difference = array_diff($new_manifest, $old_manifest);
- if (count($difference) > 0) {
- foreach ($difference as $file) {
- @unlink($this->dir_unpack . $file); // remove new files
- }
- }
- if ($this->zip->open($beforeupdate->pwd()) !== true) {
- throw new Exception(sprintf($this->lang->line('update_zip_failed_to_open'), __FUNCTION__, $beforeupdate->pwd()));
- }
- $this->verify_update($this->zip, $beforeupdate->name()); // name() w/o extension
- $this->files_processed = $this->zip->numFiles;
- $this->zip->extractTo($this->dir_unpack);
- $this->zip->close();
- rmdir_recursive($this->updates_folder);
- } catch (Exception $e) {
- @$this->zip->close();
- throw $e;
- } finally {
- @unlink($this->dir_unpack . $this->identifier_file);
- @unlink($this->dir_unpack . $this->manifest_file);
- }
- }
- /**
- * Checks to make sure update is valid
- * If so, extracts updated files to the main directory
- * BEFORE
- * Deletes old updates
- * (making sure only current update file and image to be made exists)
- * Creates an image of the site as it is
- *
- * @param string $file Path to update file
- * @return void
- */
- public function apply_update($file) {
- try {
- $file = new File($file);
- if (!$file->exists()) {
- throw new Exception(sprintf($this->lang->line('update_file_not_exist'), $file->pwd()));
- }
- $zip = new \ZipArchive;
- if ($zip->open($file->pwd()) !== true) {
- throw new Exception(sprintf($this->lang->line('update_zip_failed_to_open'), __FUNCTION__, $file->pwd()));
- }
- $this->verify_update($zip, $file->name()); // name() w/o extension
- $this->delete_old_updates($file->name); // name w/ extension
- $this->create_update($file->name() . '_beforeupdate'); // image of site before update
- $this->files_processed = $zip->numFiles;
- $zip->extractTo($this->dir_unpack);
- @unlink($this->dir_unpack . $this->identifier_file);
- if (!rename($this->dir_unpack . $this->manifest_file, $this->updates_folder . 'manifests' . DS . 'manifest_new.txt')) {
- throw new Exception($this->lang->line('update_manifest_move_error'));
- }
- $zip->close();
- } catch (\Exception $e) {
- $zip->close();
- throw $e;
- }
- }
- /**
- * Creates an update ZIP with included folders and identifier
- * Adds a manifest of updated files
- *
- * @param string $update_name
- * @throws Exception
- * @return void
- */
- public function create_update($update_name = null) {
- if (is_null($update_name)) {
- $update_name = 'sysupdate_' . date('Ymd_Hms');
- }
- $destination = $this->updates_folder . $update_name . '.zip';
- try {
- $this->mk_update_dir();
- if ($this->zip->open($destination, \ZIPARCHIVE::CREATE | \ZIPARCHIVE::OVERWRITE) !== true) {
- throw new Exception(sprintf($this->lang->line('update_zip_failed_to_create'), __FUNCTION__, $destination));
- }
- $this->identify_update($update_name);
- $dirs = @array_map(array($this, 'resolve_folder_path'), $this->folders);
- foreach ($dirs as $dir) {
- $this->zippy($dir, $destination);
- }
- $this->create_manifest();
- $this->zip->close();
- } catch (\Exception $e) {
- @$this->zip->close();
- @unlink($destination); // zip has to be closed before we remove the $destination
- throw $e; // rethrow
- }
- }
- /**
- * Checks to see if previous version exists
- *
- * @return boolean
- */
- public function previous_exists() {
- try {
- $this->find_previous_version();
- return true;
- } catch (Exception $e) {
- return false;
- }
- }
- /**
- * Finds the previous version by _beforeupdate
- *
- * @return \File
- * @throws Exception
- */
- private function find_previous_version() {
- $files = (new Folder($this->updates_folder))->find('.*\_beforeupdate.zip', true);
- $count = count($files);
- if ($count > 1) {
- throw new Exception($this->lang->line('update_previous_error_1'));
- } elseif ($count < 1) {
- throw new Exception($this->lang->line('update_previous_error_2'));
- } else {
- return new File($this->updates_folder . $files[0]);
- }
- }
- /**
- * Keeps only current file
- *
- * @param string $current_file Name of current file with ext
- * @return void
- */
- private function delete_old_updates($current_file) {
- $files = dir_files_array($this->updates_folder);
- foreach ($files as $file) {
- if ($file == $current_file) {
- continue;
- }
- @unlink($this->updates_folder . $file);
- }
- }
- /**
- * Creates a manifest/array of files that were added to zip
- *
- * @throws Exception
- * @return void
- */
- private function create_manifest() {
- $manifest = new File($this->updates_folder . 'manifests' . DS . 'manifest_old.txt', true);
- $contents = serialize($this->manifest);
- if (!$manifest->write($contents)) {
- throw new Exception($this->lang->line('update_manifest_write_error'));
- }
- $manifest->close();
- if ($this->zip->addFile($manifest->pwd(), $this->manifest_file)) {
- //$this->files_processed++;
- $this->current_file_count++;
- } else {
- @unlink($manifest->pwd());
- throw new Exception($this->lang->line('update_manifest_add_error'));
- }
- }
- /**
- * Adds an identifier file that is base64 encoded
- * version of the filename
- *
- * @param string $update_name
- * @throws Exception
- * @return void
- */
- private function identify_update($update_name) {
- if ($this->zip->addFromString($this->identifier_file, base64_encode($update_name))) {
- //$this->files_processed++;
- $this->current_file_count++;
- } else {
- throw new Exception($this->lang->line('update_id_add_error'));
- }
- }
- /**
- * Checks to make sure identifier file exists and base64 decodes to
- * match the filename
- *
- * Checks to make sure that the manifest file exists
- *
- * @param object $zip
- * @param type $update_name
- * @throws Exception
- * @return void
- */
- private function verify_update($zip, $update_name) {
- $identifier = $zip->getFromName($this->identifier_file);
- if (!$identifier || base64_decode($identifier) !== $update_name) {
- throw new Exception($this->lang->line('update_id_find_error'));
- }
- if (!$zip->getFromName($this->manifest_file)) {
- throw new Exception($this->lang->line('update_manifest_find_error'));
- }
- }
- /**
- * Creates update folder if not exists
- *
- * @throws Exception
- */
- public function mk_update_dir() {
- if (!is_dir($this->updates_folder) && mkdir($this->updates_folder, DIR_WRITE_MODE) === false) {
- throw new Exception(sprintf($this->lang->line('update_create_dir_error'), $this->updates_folder));
- }
- }
- /**
- * Resolves folder path
- *
- * @param string $folder
- * @return string $path Revised folder path
- * @throws Exception
- */
- private function resolve_folder_path($folder) {
- $path = fix_slashes($this->dir_unpack . Folder::slashTerm($folder));
- if (is_dir($path)) {
- return $path;
- } else {
- throw new Exception(sprintf($this->lang->line('update_dir_not_exist'), $path));
- }
- }
- /**
- * Creates a zip file from a single $source directory
- * All added files get added to the manifest array
- *
- * @param string $dir (path)
- * @throws Exception
- * @return void
- */
- private function zippy($dir, $destination) {
- $files = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($dir), \RecursiveIteratorIterator::SELF_FIRST);
- foreach ($files as $file) {
- if ($file->isDir()) {
- continue;
- }
- if ($file->isFile()) {
- $filename = $file->getBasename();
- if (in_array($filename, $this->excluded_files)) {
- // ignored files
- continue;
- } else {
- $this->current_file_count++; // increment curr file count
- // add file to zip
- if ($this->limit_files_per_open) {
- $this->reopen($destination);
- }
- $path = str_replace($this->dir_unpack, '', $file);
- $path = ltrim(fix_slashes($path, 'linux'), '/');
- $this->zip->addFile($file, $path); // add file
- $this->manifest[] = $path;
- $this->files_processed++; // increment files added
- }
- }
- }
- }
- /**
- * Reopens zip file $destination and resets current file count
- *
- * @param string $destination (path)
- * @throws Exception
- * @return void
- */
- private function reopen($destination) {
- if ($this->current_file_count >= $this->max_files_per_open) {
- $this->zip->close();
- $this->current_file_count = 0; // reset curr file count
- if ($this->zip->open($destination, \ZIPARCHIVE::CREATE) !== true) {
- throw new Exception(sprintf($this->lang->line('update_zip_reopen_fail'), __FUNCTION__, $destination, $this->files_processed));
- }
- }
- }
- }
Add Comment
Please, Sign In to add comment