YaWK  24.1
Yet another WebKit
YAWK\update Class Reference

The update class - handles yawk's system update functions. More...

Public Member Functions

 __construct ()
 update constructor. Check if allow_url_fopen is enabled More...
 
 fetchFiles (object $db, string $currentVersion, string $updateVersion, array $lang)
 read system/update/updateFiles.ini and fetch files from remote (GitHub) server More...
 
 generateLocalFilebase (object $db, array $lang)
 Read all files of current YaWK installation and write each file with path + MD5 hash to ini file to compare it later with the possible update files. This is used to verify the integrity of the files. More...
 
 getUpdateSettings ()
 get update settings from local update folder (system/update/update.ini) and return array|false More...
 
 isServerReachable (string $url)
 check if update server is reachable More...
 
 readUpdateFilebaseFromServer ()
 read filebase.ini from update server (https://update.yawk.io/filebase.ini) and return array|false More...
 
 readUpdateIniFromServer ()
 read update.ini from update server (https://update.yawk.io/update.ini) and return array|false More...
 
 recordMigration ($db, $successfulMigrations)
 record migration in database More...
 
 runMigrations (object $db, array $lang)
 Run the migration SQL files. More...
 

Public Attributes

string $base_dir = ''
 
string $currentVersion = ''
 
string $githubServer = 'https://raw.githubusercontent.com/YaWK/yawk.io/master/'
 
string $localUpdateSystemPath = 'system/update/'
 
bool $migrationSuccessful = false
 
string $updateFile = 'update.ini'
 
string $updateFilebase = 'filebase.ini'
 
array $updateFiles = array()
 
string $updateFilesFile = 'updateFiles.ini'
 
string $updateServer = 'https://update.yawk.io/'
 
array $updateSettings = array()
 
string $updateVersion = ''
 

Detailed Description

The update class - handles yawk's system update functions.

YaWK System Updater Class

The YaWK System Updater Class provides methods to facilitate the updating process of the system. It includes features such as checking for new versions, verifying and comparing files to ensure a stable and reliable update. This class aims to simplify the update process and minimize the risk of any errors or issues during the update.

Author
Daniel Retzl danie.nosp@m.lret.nosp@m.zl@gm.nosp@m.ail..nosp@m.com
Version
1.0.0

Definition at line 20 of file update.php.

Constructor & Destructor Documentation

◆ __construct()

YAWK\update::__construct ( )

update constructor. Check if allow_url_fopen is enabled

will be called by xhr request from admin/js/update-generateLocalFilebase.php

Definition at line 78 of file update.php.

80  {
81  // Get the value of the allow_url_fopen setting
82  $allowUrlFopen = ini_get('allow_url_fopen');
83  // Check if allow_url_fopen is enabled
84  if (!$allowUrlFopen)
85  { // allow_url_fopen is disabled, exit with error
86  // todo: syslog entry
87  echo "allow_url_fopen is disabled, but required to use the update methods. Please enable allow_url_fopen in your php.ini file or ask your admin / hoster for assistance.";
88  }
89 
90  // check if update server is reachable
91  if ($this->isServerReachable($this->updateServer.$this->updateFile) === false)
92  { // todo: syslog entry
93  echo "Update server $this->updateServer not reachable. Update not possible at the moment - please try again later.<br>";
94  }
95 
isServerReachable(string $url)
check if update server is reachable
Definition: update.php:103

References YAWK\update\isServerReachable().

Member Function Documentation

◆ fetchFiles()

bool $migrationSuccessful true false indicates if migration was successful call YAWK\update::fetchFiles ( object  $db,
string  $currentVersion,
string  $updateVersion,
array  $lang 
)

read system/update/updateFiles.ini and fetch files from remote (GitHub) server

will be called by xhr request from admin/js/update-fetchFiles.php

Parameters
$dbobject database connection
$updateVersionstring update version
$langarray language array

Definition at line 365 of file update.php.

366  : void
367  {
368  // init updateSucceed flag, will be set to true if update was successful
369  $updateSucceed = false;
370 
371  // set update version
372  $this->currentVersion = $currentVersion;
373  $this->updateVersion = $updateVersion;
374 
375  // override $this->updateServer with GitHub url
376  $this->updateServer = $this->githubServer;
377 
378  // file fetched successfully
379  $basedir = __DIR__;
380  // remove last 15 chars from $basedir (system/update/)
381  $basedir = substr($basedir, 0, -14);
382  // $basedir = substr($basedir, 0, -8);
383 
384  $response = ''; // init output string, result of the update process, will be returned to the frontend
385  // check if updateFiles.ini exists
386  if (file_exists($basedir.$this->localUpdateSystemPath . $this->updateFilesFile))
387  {
388  // updateFiles.ini exists
389  // parse updateFiles.ini into array
390  $this->updateFiles = parse_ini_file($basedir.$this->localUpdateSystemPath . $this->updateFilesFile);
391  if (count($this->updateFiles) < 1)
392  { // unable to read updateFiles.ini from local update folder
393  $response .= "<span class=\"text-warning\"><p><i class=\"fa fa-exclamation-triangle text-warning\"></i>".$lang['UPDATE_FAST_FORWARD_INFO']."
394  <a href=\"#fastForwardUpdate\" id=\"fastForwardUpdateBtn\" class=\"btn btn-warning\">".$lang['UPDATE_FAST_FORWARD_BTN']." &nbsp;<i class=\"fa fa-fast-forward\"></i></a></span><br>";
395  }
396  else
397  { // count elements of updateFiles array
398  $totalUpdateFiles = count($this->updateFiles);
399  $failedFiles = 0;
400  $successFiles = 0;
401  $fetchFailed = 0;
402  $fetchSucceed = 0;
403  $processedFiles = 0;
404 
405  // updateFiles.ini read successfully
406  // fetch files from remote server
407  foreach ($this->updateFiles as $key => $value)
408  {
409  $processedFiles++;
410  // debug line can be removed $response .= "VALUE: $value <br>";
411 
412  // build file url
413  $fileUrl = $this->updateServer . $value;
414  // fetch next file to update
415  $file = file_get_contents($fileUrl);
416  if ($file === false)
417  {
418  // unable to fetch file
419  $response .= $lang['UPDATE_FETCH_FILE_FAILED'].$fileUrl."<br>";
420  $fetchFailed++;
421  }
422  else
423  { // count successful fetches
424  $fetchSucceed++;
425 
426  // Write file to local system
427  if (!file_put_contents($basedir.$value, $file))
428  { // unable to write file to local system
429  $failedFiles++; // count failed files
430  $response .= "<b> class=\"text-danger\">".$lang['UPDATE_UNABLE_TO_WRITE_FILE']."</b> " .$basedir.$value . "<br>";
431  }
432  else
433  { // file written successfully
434  $successFiles++; // count successful written files
435  $response .= "<b class=\"text-success animated fadeIn slow\">".$lang['UPDATE_FILE_WRITTEN']."</b> " . $basedir.$value . "<br>";
436  }
437  }
438  }
439  // check if all files were fetched successfully
440  if ($fetchFailed > 0)
441  { // at least one file could not be fetched
442  $response .= "<b class=\"text-danger\">".$lang['UNABLE_TO_FETCH_FILES_FROM_REMOTE_SERVER']." $fetchFailed</b><br>";
443  }
444  else if ($fetchSucceed === $totalUpdateFiles)
445  { // all files fetched successfully
446  $response .= "<b class=\"text-success\">$fetchSucceed ".$lang['UPDATE_SUCCESSFULLY_FETCHED']."</b><br>";
447  }
448  // check if all files were written successfully
449  if ($failedFiles > 0)
450  { // at least one file could not be written
451  $response .= "<b class=\"text-danger\">$failedFiles ".$lang['UPDATE_FAILED_FILES']."</b><br>";
452  }
453  else if ($successFiles === $totalUpdateFiles)
454  { // all files written successfully
455  $response .= "<b class=\"text-success\">".$lang['ALL']." ".$successFiles." ".$lang['UPDATE_ALL_FILES_SUCCESS']."</b><br>";
456  }
457  // check if all files were processed
458  if ($processedFiles === $totalUpdateFiles)
459  { // all files processed
460  $response .= "<b class=\"text-success\">".$lang['ALL']." ".$processedFiles." ".$lang['UPDATE_FILES_PROCESSED']."</b><br>";
461  }
462  else
463  { // not all files processed
464  $response .= "<b class=\"text-danger\">".$lang['UPDATE_NOT_ALL_FILES_PROCESSED']." ".$processedFiles." ".$lang['OF']." ".$totalUpdateFiles." ".$lang['UPDATE_FILES_PROCESSED'].".</b><br>";
465  }
466  // check if update was successful
467  if ($successFiles === $totalUpdateFiles)
468  { // update was successful
469  $updateSucceed = true;
470  }
471  else
472  { // update failed
473  $response .= "<h3 class=\"text-danger\">".$lang['UPDATE_FAILED']."</h3>";
474  }
475  }
476  }
477  else
478  { // updateFiles.ini does not exist
479  $response .= "<span class=\"text-danger\"><b>".$lang['ERROR'].":</b> ".$lang['UPDATE_FILES_INI_MISSING']." " .$basedir.$this->localUpdateSystemPath . $this->updateFilesFile . "</span>";
480  }
481 
482  // check if update was successful
483  if ($updateSucceed === true)
484  { // set new version in database
485  settings::setSetting($db, "yawkversion", $updateVersion, $lang);
486 
487  // get version from database to check if it was updated correctly
488  $version = settings::getSetting($db, "yawkversion");
489  if ($version == $updateVersion && $updateSucceed === true)
490  { // system version was updated successfully
491  $response .= "<h3 class=\"text-success\">".$lang['UPDATE_TO']." $updateVersion ".$lang['COMPLETED_SUCCESSFULLY']."</b><h3>";
492  sys::setSyslog($db, 54, 0, "<b>UPDATE COMPLETE</b> Migration and Files updated to $updateVersion.", 0, 0, 0, 0);
493  }
494  else
495  { // failed to update version in database
496  $response .= "<h3 class=\"text-danger\">".$lang['UPDATE_FAILED_TO_WRITE_VERSION_NUMBER']." ($updateVersion)</h3>";
497  }
498  }
499  else
500  { // update failed
501  $response .= "<h3 class=\"text-danger\">".$lang['UPDATE_FAILED_FROM']." $this->currentVersion ".$lang['TO']." $updateVersion.</h3>";
502  }
503  // return xhr response
504  echo $response;
505 
506  // close database connection
507  $db->close();
print $lang['FILEMAN_UPLOAD']
static setSetting($db, $property, $value, $lang)
Set value for property into settings database.
Definition: settings.php:502
static getSetting($db, $property)
Get and return value for property from settings database.
Definition: settings.php:470
string $currentVersion
Definition: update.php:37
string $updateVersion
Definition: update.php:42
string $githubServer
Definition: update.php:29
foreach($updateFilebase as $key=> $value) foreach($localFilebase as $filePath=> $localHash) $response
$value

References YAWK\update\$currentVersion, $db, YAWK\update\$githubServer, $lang, $response, YAWK\update\$updateVersion, $value, YAWK\settings\getSetting(), and YAWK\settings\setSetting().

◆ generateLocalFilebase()

YAWK\update::generateLocalFilebase ( object  $db,
array  $lang 
)

Read all files of current YaWK installation and write each file with path + MD5 hash to ini file to compare it later with the possible update files. This is used to verify the integrity of the files.

Parameters
$dbobject global db object
$langarray global language array
Returns
void

Definition at line 546 of file update.php.

547  : void
548  {
549  $this->base_dir = dirname(__FILE__);
550  $this->base_dir = substr($this->base_dir, 0, -15); // remove last 15 chars
551  // echo "<p>Base directory: $this->base_dir</p>";
552 
553  // set path and filename of the ini file
554  $updatePath = '/system/update/';
555  $updateFolder = $this->base_dir.$updatePath;
556 
557  if (!is_dir($updateFolder)){
558  if (!mkdir($updateFolder, 0777, true) && !is_dir($updateFolder)) {
559  throw new \RuntimeException(sprintf('Unable to create "%s" - please check folder permissions or create folder by hand', $updateFolder));
560  }
561  }
562  $iniFileName = 'filebase.current.ini';
563  $input_folder = $this->base_dir;
564  $output_file = $updateFolder.$iniFileName;
565  $writeIniFile = true;
566 
567  // delete old file if exists
568  if (is_file($output_file)){
569  unlink($output_file);
570  }
571 
572  // Open the output file for writing
573  $output_handle = fopen($output_file, 'w');
574  if (!$output_handle) {
575  // handle the error (e.g. show an error message or log the error)
576  die("Failed to open file for writing: $output_file");
577  }
578 
579  // Get the full path of the input folder
580  $input_folder = realpath($input_folder);
581 
582  // Loop through all files in the input folder and its subfolders
583  echo "<p>".$lang['UPDATE_BUILDING_LOCAL_FILEBASE']." <i><small>$input_folder</small></i></p>";
584  $root_files = array();
585  $subfolder_files = array();
586  foreach(new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($input_folder)) as $file_path)
587  {
588  // Skip some excluded directories and hidden files
589  if ($file_path->isDir()
590  || $file_path->getFilename()[0] == '.'
591  || strpos($file_path, '/.git/') !== false
592  || strpos($file_path, '/.github/') !== false
593  || strpos($file_path, '/.idea/') !== false
594  || strpos($file_path, '/content/') !== false
595  || strpos($file_path, '/media/') !== false)
596  { // skip this file/folder
597  continue;
598  }
599 
600  // Calculate the MD5 hash of the file
601  $md5_hash = md5_file($file_path);
602 
603  // Get the full path of the file
604  $full_path = realpath($file_path);
605 
606  // Remove the input folder path from the full path to get the relative path
607  $relative_path = substr($full_path, strlen($input_folder) + 1);
608 
609  // Split the relative path into an array of path components
610  $path_components = explode('/', $relative_path);
611 
612  // Check if the path has only one component (i.e. it's a file in the root folder)
613  if (count($path_components) == 1) {
614  $root_files[$relative_path] = $md5_hash;
615  } else {
616  $subfolder_files[$relative_path] = $md5_hash;
617  }
618  }
619 
620  // Sort the arrays alphabetically by key (the relative path)
621  ksort($root_files);
622  ksort($subfolder_files);
623 
624  // Merge the two arrays so that the root files are listed first
625  $hashes = array_merge($root_files, $subfolder_files);
626 
627  // init counters
628  $totalFiles = count($hashes); // count total files
629  $totalFilesVerified = 0; // number of verified files
630  $totalFilesFailed = 0; // number of failed files
631 
632  // Write the sorted array to the output file in the .ini format
633  foreach ($hashes as $relative_path => $md5_hash)
634  { // write each file with its md5 hash to ini file
635  // echo "Writing $relative_path=$md5_hash to $output_file\n";
636  // Write the relative path and MD5 hash to the output file
637  if (file_put_contents($output_file, "$relative_path=$md5_hash\n", FILE_APPEND))
638  { // line written successfully
639  // echo '<p class="text-success">Verified '.$relative_path.' <small>'.$md5_hash.'</small></p>';
640  $totalFilesVerified++;
641  }
642  else
643  { // line failed
644  // echo '<p class="text-danger">Failed '.$relative_path.' <small>'.$md5_hash.'</small></p>';
645  $totalFilesFailed++;
646  }
647  }
648 
649  // Close the output file
650  echo '<p class="animated fadeIn slow delay-1s">'.$lang['UPDATE_INDEXING'].' <b>'.$totalFiles.'</b> '.$lang['FILES'].'. '.$lang['VERIFIED'].' <b>'.$totalFilesVerified.'</b> '.$lang['FILES'].'. '.$lang['FAILED'].' <b>'.$totalFilesFailed.'</b> '.$lang['FILES'].'.</p>';
651 
652  if (!is_file($output_file))
653  { // unable to write ini file
654  $iniFileWritten = "<h4 class=\"text-danger\">".$iniFileName." ".$lang['COULD_NOT_BE_WRITTEN']."</h4>";
655  }
656  else
657  { // ini file written successfully
658  $iniFileWritten = "<p class=\"animated fadeIn slow delay-5s\">".$lang['UPDATE_HASH_VALUES_WRITTEN_TO']." <b><a href=\"$updatePath$iniFileName\" target=\"_blank\">$updatePath$iniFileName</a></b></p>";
659  }
660 
661  // check if all files were verified
662  if ($totalFiles == $totalFilesVerified)
663  { // set success icon, message and colors
664  $icon = '<i class="fa fa-check-circle-o fa-2x text-success"></i>';
665  $done = "<h4 class=\"text-success animated fadeIn slow delay-4s\">".$totalFiles."&nbsp;".$lang['UPDATE_VERIFICATION_SUCCESS']."</h4>";
666  $iconFalse = '';
667  $successColor = ' text-success';
668  $failedColor = '';
669  }
670  else
671  { // set failure icon, message and colors
672  $iconFalse = '<i class="fa fa-exclamation-triangle fa-2x text-danger"></i>';
673  $done = "<h4 class=\"text-danger\"><b>".$totalFilesFailed." ".$lang['UPDATE_VERIFICATION_FAILED']."</b></h4>";
674  $failedColor = ' text-danger';
675  $successColor = '';
676  }
677 
678  echo "
679  <p class=\"animated fadeIn slow delay-2s$successColor\">$icon &nbsp;".$lang['UPDATE_GENERATED_HASH_VALUES']." <b>$totalFilesVerified / $totalFiles</b></p>";
680  echo"<h4 class=\"animated fadeIn slow delay-4s\">$done</h4>
681  $iniFileWritten";
682 
683  // check if any files failed
684  if ($totalFilesFailed > 0)
685  { // show amount of failed files
686  echo"<p class=\"animated fadeIn slow delay-3s$failedColor\">$iconFalse &nbsp;".$lang['UPDATE_FAILED_TO_VERIFY']." <b>$totalFilesFailed</b></p>";
687  }
688 
689  // Close the output file
690  if (!fclose($output_handle))
691  { // unable to close ini file
692  echo '<p class="animated fadeIn slow delay-5s">failed to close: '.$updateFolder.$iniFileName.'</p>';
693  }
die
Definition: block-user.php:27
string $base_dir
Definition: update.php:23

References YAWK\update\$base_dir, $lang, and die.

◆ getUpdateSettings()

YAWK\update::getUpdateSettings ( )

get update settings from local update folder (system/update/update.ini) and return array|false

will be called by xhr request from admin/js/update-generateLocalFilebase.php

Returns
array|false

Definition at line 131 of file update.php.

132  : array|false
133  {
134  // read update.ini from local update folder
135  $this->updateSettings = parse_ini_file($this->localUpdateSystemPath.$this->updateFile);
136  if (count($this->updateSettings) < 1)
137  { // unable to read update.ini from local update folder
138  echo "Error: Unable to read update.ini from local update folder. Check if this file exists: ".$this->localUpdateSystemPath.$this->updateFile;
139  }
140  else {
141  // update.ini read successfully
142  // set update version
143  $this->updateVersion = $this->updateSettings['version'];
144 
145  // return update settings array
146  return $this->updateSettings;
147  }
148  // return false if something went wrong
149  return false;
array $updateSettings
Definition: update.php:57

References YAWK\update\$updateSettings.

◆ isServerReachable()

YAWK\update::isServerReachable ( string  $url)

check if update server is reachable

returns true if server is reachable, false if not

Parameters
$urlstring url to check
Returns
bool true|false

Definition at line 103 of file update.php.

104  : bool
105  {
106  $ch = curl_init($url);
107  curl_setopt($ch, CURLOPT_NOBODY, true);
108  curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
109  curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 30);
110  curl_setopt($ch, CURLOPT_TIMEOUT, 30);
111  curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
112  curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
113  curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (compatible; UpdateClient/1.0)');
114 
115  $response = curl_exec($ch);
116  $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
117 
118  curl_close($ch);
119 
120  if ($httpCode >= 200 && $httpCode < 300) {
121  return true;
122  } else {
123  return false;
124  }
$url
Definition: user-new.php:101

References $response, and $url.

Referenced by YAWK\update\__construct().

◆ readUpdateFilebaseFromServer()

YAWK\update::readUpdateFilebaseFromServer ( )

read filebase.ini from update server (https://update.yawk.io/filebase.ini) and return array|false

will be called by xhr request from admin/js/update-readUpdateFilebase.php The filebase.ini contains a list of all files with their md5 hash. This function returns the filebase as array. (to compare it later with the local filebase)

Returns
array|false

Definition at line 702 of file update.php.

703  : array|false
704  {
705  // URL of the remote INI file
706  $url = $this->updateServer.'filebase.ini';
707 
708  // Get the content of the remote INI file
709  $iniContent = file_get_contents($url);
710 
711  // Check if the content was retrieved successfully
712  if ($iniContent !== false)
713  { // Parse the INI content into an associative array
714  $filebase = parse_ini_string($iniContent);
715 
716  // Print the contents of the array
717  foreach ($filebase as $key => $value)
718  { // set update array
719  $updateFilebase[$key] = $value;
720  }
721  }
722  else
723  { // unable to read filebase from remote server
724  echo "Error: Unable to read filebase from remote server. Check if this file exists: $url";
725  }
726  // return array or false
727  return $updateFilebase ?? false;
string $updateFilebase
Definition: update.php:52

References YAWK\update\$updateFilebase, $url, and $value.

◆ readUpdateIniFromServer()

YAWK\update::readUpdateIniFromServer ( )

read update.ini from update server (https://update.yawk.io/update.ini) and return array|false

Returns
false|array

Definition at line 513 of file update.php.

514  : false|array
515  {
516  // URL of the remote INI file
517  $url = $this->updateServer.$this->updateFile;
518 
519  // Get the content of the remote INI file
520  $iniContent = file_get_contents($url);
521 
522  // Check if the content was retrieved successfully
523  if ($iniContent !== false)
524  { // Parse the INI content into an associative array
525  $config = parse_ini_string($iniContent);
526 
527  // Print the contents of the array
528  foreach ($config as $key => $value)
529  { // set update array
530  $updateConfig['UPDATE'][$key] = $value;
531  }
532  }
533  else
534  { // unable to read update.ini from remote server
535  echo "Error: Unable to read the remote INI file.";
536  }
537  return $updateConfig ?? false;

References $url, and $value.

◆ recordMigration()

YAWK\update::recordMigration (   $db,
  $successfulMigrations 
)

record migration in database

will be called from runMigrations() if migration was successful

Parameters
$db
$successfulMigrations
Returns
void

Definition at line 159 of file update.php.

160  : void
161  {
162  $output = '';
163  // check if migrations array is set and got at least 1 entry
164  if (is_array($successfulMigrations) && (count($successfulMigrations) > 0))
165  { // loop through all migrations
166  foreach ($successfulMigrations as $migrationVersion) {
167  // record migration
168  if (!$db->query("INSERT INTO {migrations} (`version`, `executed_at`) VALUES ('$migrationVersion', NOW())"))
169  { // error recording migration
170  sys::setSyslog($db, 53, 0, "Error recording migration for version $migrationVersion: " . $db->error . " ", 0, 0, 0, 0);
171  $output .= "Error recording migration for version $migrationVersion: " . $db->error . "<br>";
172  }
173  else
174  { // migration recorded successfully
175  sys::setSyslog($db, 53, 0, "Migration record for version $migrationVersion successful.", 0, 0, 0, 0);
176  $output .= "Migration for version $migrationVersion executed successfully.<br>";
177  }
178  }
179  }
180  else
181  { // no migrations to record
182  sys::setSyslog($db, 54, 0, "No Migrations to record. Is there a logical error?", 0, 0, 0, 0);
183  $output .= "No migrations to record.<br>";
184  }
185  echo $output;

References $db.

Referenced by YAWK\update\runMigrations().

◆ runMigrations()

YAWK\update::runMigrations ( object  $db,
array  $lang 
)

Run the migration SQL files.

If update.ini contains migration files between the current version and the update version, this function will be called

Parameters
$dbobject the database object
$langarray the language array
Returns
void true|false if migrations were successful or not
Parameters
$dbdb

Definition at line 194 of file update.php.

195  : void
196  {
197  require_once 'sys.php';
198  /** @param $db db */
199  ini_set('display_errors', 1);
200  error_reporting(E_ALL);
201 
202  // init variables
203  $output = '';
204  $totalMigration = 0;
205  $successfulMigrations = 0;
206  $failedMigrations = 0;
207  $successfulMigrationVersions = array();
208 
209  // log start of migration
210  sys::setSyslog($db, 56, 0, "runMigrations initialized. Updating from $this->currentVersion to $this->updateVersion", 0, 0, 0, 0);
211 
212  // run migrations
213  try
214  { // Start transaction, so we can roll back if something goes wrong
215  $db->beginTransaction();
216 
217  // Determine which migrations need to be executed
218  $migrationUrlBase = $this->updateServer . 'migration-';
219  $currentVersionParts = explode('.', $this->currentVersion);
220  $updateVersionParts = explode('.', $this->updateVersion);
221  // Start at the next minor version after the current version
222  $startIndex = (int)$currentVersionParts[2] + 1;
223  // End at the minor version of the update version
224  $endIndex = (int)$updateVersionParts[2];
225  $output .= '<br><br><div class="panel-group animated fadeIn slow delay-2s" id="accordion" role="tablist" aria-multiselectable="true">
226  <div class="panel panel-default">
227  <div class="panel-heading" role="tab" id="headingMigration">
228  <h4 class="panel-title">
229  <a class="collapsed" role="button" data-toggle="collapse" data-parent="#accordion" href="#collapseMigration" aria-expanded="true" aria-controls="collapseMigration">
230  '.$lang['UPDATE_MIGRATIONS'].'<br>
231  <small>(database updates)</small>
232  </a>
233  </h4>
234  </div>
235  <div id="collapseMigration" class="panel-collapse collapse" role="tabpanel" aria-labelledby="headingMigration">
236  <div class="panel-body">';
237 
238  // Loop through the migration files
239  for ($i = $startIndex; $i <= $endIndex; $i++)
240  {
241  $totalMigration++;
242  // build migration version
243  $migrationVersion = $currentVersionParts[0] . '.' . $currentVersionParts[1] . '.' . $i;
244  // build migration filename
245  $migrationUrl = $migrationUrlBase . $migrationVersion . '.sql';
246 
247  // check if migration was already executed
248  $migrationRecord = $db->query("SELECT version FROM {migrations} WHERE version = '$migrationVersion'")->fetch_assoc();
249 
250  // check if migration was already executed
251  if ($migrationRecord !== null)
252  { // migration was already executed
253  $output .= "$migrationVersion : ".$lang['UPDATE_MIGRATION_ALREADY_EXEC']."<br>";
254  sys::setSyslog($db, 53, 1, "Migration for build $migrationVersion was already executed.", 0, 0, 0, 0);
255  $failedMigrations++;
256  continue;
257  }
258  else {
259  // migration was not executed yet
260  // $output .= "Migration for build $migrationVersion was not executed yet.<br>";
261  // Fetch the migration file
262  $migrationSql = @file_get_contents($migrationUrl);
263  }
264 
265  // Check if the migration file was fetched successfully
266  if ($migrationSql === false)
267  { // Unable to fetch migration file
268  $output .= $lang["UPDATE_NO_MIGRATION_REQUIRED_FOR_BUILD"]." ".$migrationVersion."<br>";
269  sys::setSyslog($db, 53, 0, "No migration required for build $migrationVersion", 0, 0, 0, 0);
270  $failedMigrations++;
271  continue;
272  }
273  else
274  { // Fetched migration file successfully
275  $output .= "<span style=\"text-success\"><b>".$lang['UPDATE_FETCHED_MIGRATION_FILE_FROM']."</b>".$migrationUrl."</span><br>";
276  sys::setSyslog($db, 54, 0, "<b>Fetched migration file</b> from $migrationUrl", 0, 0, 0, 0);
277  $successfulMigrations++;
278  $successfulMigrationVersions[] = $migrationVersion;
279  }
280 
281  $output .= "Multi-query SQL: " . $migrationSql . "<br>";
282 
283  // explode the migration file into individual queries (array)
284  $sqlStatements = explode(';', $migrationSql);
285  // to keep track of the statement number
286  $statementCounter = 0;
287  // loop through all sql queries of current migration file
288  foreach ($sqlStatements as $sqlStatement)
289  { // increment statement counter
290  $statementCounter++;
291  // trim the sql statement
292  $sqlStatement = trim($sqlStatement);
293  // check if sql statement is not empty
294  if (!empty($sqlStatement))
295  { // execute the sql statement
296  if (!$db->query($sqlStatement))
297  { // migration failed
298  $output .= $migrationVersion." ".$lang['UPDATE_ERROR_EXEC_FAILED']." ".$statementCounter . $db->error . "<br>";
299  sys::setSyslog($db, 56, 2, "Error executing migration statement #$statementCounter for version (query failed) $migrationVersion: " . $db->error . " ", 0, 0, 0, 0);
300  $db->rollback(); // Rollback the transaction
301  return;
302  }
303  else
304  { // migration successful
305  $output .= "<span style=\"text-success\">$migrationVersion ".$lang['UPDATE_ERROR_EXEC_SUCCESS']." $statementCounter</span><br>";
306  sys::setSyslog($db, 53, 0, "executed migration statement #$statementCounter : $migrationUrlBase$migrationVersion.sql ", 0, 0, 0, 0);
307  }
308  }
309  }
310  } // end loop through migration files
311 
312  // Commit the transaction if all migrations executed successfully
313  $db->commit();
314 
315  // if there was at least one successful migration
316  if ($successfulMigrations > 0)
317  { // store migration version in database
318  $this->recordMigration($db, $successfulMigrationVersions);
319  foreach ($successfulMigrationVersions as $successfulMigrationVersion)
320  { // output successful migration version
321  $output .= "<span style=\"text-success\">$successfulMigrationVersion ".$lang['UPDATE_MIGRATION_RECORDED']."</span><br>";
322  }
323  // log successful migration
324  sys::setSyslog($db, 54, 0, "<b>Migration complete</b>Migrations executed successfully.", 0, 0, 0, 0);
325  $this->migrationSuccessful = true;
326  }
327  // END migrations executed successfully
328  }
329  // TRANSACTION FAILED - ROLLBACK
330  catch (\Exception $e)
331  { // An exception was thrown, rollback the transaction
332  if ($db->rollback() === true)
333  { // rollback successful
334  sys::setSyslog($db, 56, 2, "<b>Rolled back transaction</b> because there was an error executing migrations: " . $e->getMessage() ." ", 0, 0, 0, 0);
335  $output .= $lang['UPDATE_MIGRATION_ROLLED_BACK'] . $e->getMessage() . "\n";
336  }
337  else
338  { // rollback failed
339  sys::setSyslog($db, 56, 2, "<b>Rollback FAILED!</b>, additionally there was an error during migrations: " . $e->getMessage() ." ", 0, 0, 0, 0);
340  $output .= $lang['UPDATE_MIGRATION_ROLLBACK_FAILED'] . $e->getMessage() . "\n";
341  }
342  $this->migrationSuccessful = false;
343  }
344  // close migration panel body+panel
345  $output .= "</div></div></div>";
346 
347  // output ajax response
348  if (!empty($output))
349  { // will be returned to ajax request
350  echo $output;
351  }
352  else
353  { // no output was generated - this should not happen
354  sys::setSyslog($db, 56, 2, "No migrations were executed. Output is empty. output was not filled with any value during runMigrations(). (this is not possible?!)", 0, 0, 0, 0);
355  echo $lang['UPDATE_NO_MIGRATION_EXECUTED'];
356  }
recordMigration($db, $successfulMigrations)
record migration in database
Definition: update.php:159
$i

References $db, $i, $lang, and YAWK\update\recordMigration().

Member Data Documentation

◆ $base_dir

string YAWK\update::$base_dir = ''

Definition at line 23 of file update.php.

Referenced by YAWK\update\generateLocalFilebase().

◆ $currentVersion

string YAWK\update::$currentVersion = ''

Definition at line 37 of file update.php.

Referenced by YAWK\update\fetchFiles().

◆ $githubServer

string YAWK\update::$githubServer = 'https://raw.githubusercontent.com/YaWK/yawk.io/master/'

Definition at line 29 of file update.php.

Referenced by YAWK\update\fetchFiles().

◆ $localUpdateSystemPath

string YAWK\update::$localUpdateSystemPath = 'system/update/'

Definition at line 47 of file update.php.

◆ $migrationSuccessful

bool YAWK\update::$migrationSuccessful = false

Definition at line 72 of file update.php.

◆ $updateFile

string YAWK\update::$updateFile = 'update.ini'

Definition at line 32 of file update.php.

◆ $updateFilebase

string YAWK\update::$updateFilebase = 'filebase.ini'

Definition at line 52 of file update.php.

Referenced by YAWK\update\readUpdateFilebaseFromServer().

◆ $updateFiles

array YAWK\update::$updateFiles = array()

Definition at line 67 of file update.php.

◆ $updateFilesFile

string YAWK\update::$updateFilesFile = 'updateFiles.ini'

Definition at line 62 of file update.php.

◆ $updateServer

string YAWK\update::$updateServer = 'https://update.yawk.io/'

Definition at line 26 of file update.php.

◆ $updateSettings

array YAWK\update::$updateSettings = array()

Definition at line 57 of file update.php.

Referenced by YAWK\update\getUpdateSettings().

◆ $updateVersion

string YAWK\update::$updateVersion = ''

Definition at line 42 of file update.php.

Referenced by YAWK\update\fetchFiles().


The documentation for this class was generated from the following file: