From 7ed8976ead952b674d7f57230b4d0576a361bf5f Mon Sep 17 00:00:00 2001 From: Duncan Cameron Date: Sat, 18 Dec 2021 10:38:38 +0000 Subject: [PATCH 1/3] Get the installed version from the config table. Show update available only when the installed version is lower than the latest version. --- index.php | 42 ++++++++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/index.php b/index.php index fb58bc9..a65264e 100755 --- a/index.php +++ b/index.php @@ -83,16 +83,16 @@ public function availableUpdate() */ public function getCurrentVersion() { - $version = file_get_contents('../admin/init.php'); - $matches = array(); - preg_match_all('/define\(\"VERSION\",\"(.*)\"\);/', $version, $matches); + $table_name = $this->table_prefix . 'config'; + $prepStmt = $this->getConnection()->prepare("SELECT value FROM {$table_name} WHERE item=?"); + $prepStmt->execute(['version']); + $result = $prepStmt->fetch(PDO::FETCH_ASSOC); - if (isset($matches[1][0])) { - return $matches[1][0]; + if ($result === false) { + throw new UpdateException('No production version found.'); } - throw new UpdateException('No production version found.'); - + return $result['value']; } /** @@ -103,18 +103,25 @@ public function getCurrentVersion() function checkIfThereIsAnUpdate() { $serverResponse = $this->getResponseFromServer(); - $version = isset($serverResponse['version']) ? $serverResponse['version'] : ''; - $versionString = isset($serverResponse['versionstring']) ? $serverResponse['versionstring'] : ''; - if ($version !== '' && $version !== $this->getCurrentVersion() && version_compare($this->getCurrentVersion(), $version)) { - $this->availableUpdate = true; - $updateMessage = 'Update to ' . htmlentities($versionString) . ' is available. '; + if (isset($serverResponse['version']) && isset($serverResponse['versionstring'])) { + $version = $serverResponse['version']; + $versionString = $serverResponse['versionstring']; + + if (version_compare($this->getCurrentVersion(), $version) < 0) { + $this->availableUpdate = true; + $updateMessage = 'Update to ' . htmlentities($versionString) . ' is available. '; + + if (isset($serverResponse['autoupdater']) + && !($serverResponse['autoupdater'] === 1 || $serverResponse['autoupdater'] === '1')) { + $this->availableUpdate = false; + $updateMessage .= '
The automatic updater is disabled for this update.'; + } + } else { + $updateMessage = 'phpList is up-to-date.'; + } } else { - $updateMessage = 'phpList is up-to-date.'; - } - if ($this->availableUpdate && isset($serverResponse['autoupdater']) && !($serverResponse['autoupdater'] === 1 || $serverResponse['autoupdater'] === '1')) { - $this->availableUpdate = false; - $updateMessage .= '
The automatic updater is disabled for this update.'; + $updateMessage = 'Unable to identify new version'; } return $updateMessage; @@ -802,7 +809,6 @@ function replaceNewUpdater() echo json_encode(array('status' => $statusJson, 'autocontinue' => true)); break; case 1: - $currentVersion = $update->getCurrentVersion(); $updateMessage = $update->checkIfThereIsAnUpdate(); $isThereAnUpdate = $update->availableUpdate(); if ($isThereAnUpdate === false) { From 6574f353cfc59a4abc0d3639cf4a2674a89ddb9c Mon Sep 17 00:00:00 2001 From: Duncan Cameron Date: Sat, 18 Dec 2021 15:52:22 +0000 Subject: [PATCH 2/3] Remove the check for downgrade action because it is now redundant --- index.php | 46 +++++++++++----------------------------------- 1 file changed, 11 insertions(+), 35 deletions(-) diff --git a/index.php b/index.php index a65264e..2eb3fa7 100755 --- a/index.php +++ b/index.php @@ -423,22 +423,6 @@ function downloadUpdate() } - /** - * Check the downloaded phpList version. Return false if it's a downgrade. - * @throws UpdateException - * @return bool - */ - function checkForDowngrade() - { - $downloadedVersion = file_get_contents(self::DOWNLOAD_PATH.'/phplist/public_html/lists/admin/init.php'); - preg_match_all('/define\(\"VERSION\",\"(.*)\"\);/', $downloadedVersion, $matches); - - if (isset($matches[1][0]) && version_compare($this->getCurrentVersion(), $matches[1][0])) { - return true; - } - return false; - } - /** * Creates temporary dir * @throws UpdateException @@ -892,13 +876,6 @@ function replaceNewUpdater() } break; case 10: - if ($update -> checkForDowngrade()) { - echo (json_encode(array('continue' => true, 'autocontinue' => true, 'response' => 'Not a downgrade!'))); - } else { - echo(json_encode(array('continue' => false, 'response' => 'Downgrade is not supported.'))); - } - break; - case 11: $on = $update->addMaintenanceMode(); if ($on === false) { echo(json_encode(array('continue' => false, 'response' => 'Cannot set the maintenance mode on!'))); @@ -906,7 +883,7 @@ function replaceNewUpdater() echo(json_encode(array('continue' => true, 'response' => 'Set maintenance mode on', 'autocontinue' => true))); } break; - case 12: + case 11: try { $update->replacePHPEntryPoints(); echo(json_encode(array('continue' => true, 'response' => 'Replaced entry points', 'autocontinue' => true))); @@ -914,7 +891,7 @@ function replaceNewUpdater() echo(json_encode(array('continue' => false, 'response' => $e->getMessage()))); } break; - case 13: + case 12: try { $update->movePluginsInTempFolder(); echo(json_encode(array('continue' => true, 'response' => 'Backing up the plugins', 'autocontinue' => true))); @@ -922,7 +899,7 @@ function replaceNewUpdater() echo(json_encode(array('continue' => false, 'response' => $e->getMessage()))); } break; - case 14: + case 13: try { $update->deleteFiles(); echo(json_encode(array('continue' => true, 'response' => 'Old files have been deleted!', 'autocontinue' => true))); @@ -930,7 +907,7 @@ function replaceNewUpdater() echo(json_encode(array('continue' => false, 'response' => $e->getMessage()))); } break; - case 15: + case 14: try { $update->moveNewFiles(); echo(json_encode(array('continue' => true, 'response' => 'Moved new files in place!', 'autocontinue' => true))); @@ -939,7 +916,7 @@ function replaceNewUpdater() echo(json_encode(array('continue' => false, 'response' => $e->getMessage()))); } break; - case 16: + case 15: try { $update->movePluginsInPlace(); echo(json_encode(array('continue' => true, 'response' => 'Moved plugins in place!', 'autocontinue' => true))); @@ -947,7 +924,7 @@ function replaceNewUpdater() echo(json_encode(array('continue' => false, 'response' => $e->getMessage()))); } break; - case 17: + case 16: try { $update->moveEntryPHPpoints(); echo(json_encode(array('continue' => true, 'response' => 'Moved new entry points in place!', 'autocontinue' => true))); @@ -955,7 +932,7 @@ function replaceNewUpdater() echo(json_encode(array('continue' => false, 'response' => $e->getMessage()))); } break; - case 18: + case 17: try { $update->moveUpdater(); echo(json_encode(array('continue' => true, 'response' => 'Moved new entry points in place!', 'autocontinue' => true))); @@ -963,7 +940,7 @@ function replaceNewUpdater() echo(json_encode(array('continue' => false, 'response' => $e->getMessage()))); } break; - case 19: + case 18: try { $update->deleteTemporaryFiles(); echo(json_encode(array('continue' => true, 'response' => 'Deleted temporary files!', 'autocontinue' => true))); @@ -971,7 +948,7 @@ function replaceNewUpdater() echo(json_encode(array('continue' => false, 'response' => $e->getMessage()))); } break; - case 20: + case 19: try { $update->removeMaintenanceMode(); echo(json_encode(array('continue' => true, 'response' => 'Removed maintenance mode', 'autocontinue' => true))); @@ -979,7 +956,7 @@ function replaceNewUpdater() echo(json_encode(array('continue' => false, 'response' => $e->getMessage()))); } break; - case 21: + case 20: $writeStep = false; try { $update->replaceNewUpdater(); @@ -1864,7 +1841,7 @@ function setCurrentActionItem(step) { 7: 1, 8: 2, 9: 2, - 10: 2, + 10: 3, 11: 3, 12: 3, 13: 3, @@ -1875,7 +1852,6 @@ function setCurrentActionItem(step) { 18: 3, 19: 3, 20: 3, - 21: 3, }; let steps = document.querySelectorAll('.step-image'); From 59a3662b03fb08d1740422519f561f3a86310c3e Mon Sep 17 00:00:00 2001 From: Duncan Cameron Date: Sun, 19 Dec 2021 14:28:14 +0000 Subject: [PATCH 3/3] Throw an exception when downloading or unzipping the new release file fails. Catch any unhandled exception to be able to send a json response to the browser. --- index.php | 376 +++++++++++++++++++++++++++--------------------------- 1 file changed, 191 insertions(+), 185 deletions(-) diff --git a/index.php b/index.php index 2eb3fa7..2f6f152 100755 --- a/index.php +++ b/index.php @@ -414,7 +414,7 @@ function downloadUpdate() curl_setopt($ch, CURLOPT_FILE, fopen($zipFile, 'w+')); $page = curl_exec($ch); if (!$page) { - echo "Error :- " . curl_error($ch); + throw new \UpdateException('Error: ' . curl_error($ch)); } curl_close($ch); @@ -589,7 +589,9 @@ function unZipFiles($toBeExtracted, $extractPath) throw new \UpdateException("Error: Unable to open the Zip File"); } /* Extract Zip File */ - $zip->extractTo($extractPath); + if (!$zip->extractTo($extractPath)) { + throw new \UpdateException("Error: Unable to extract the Zip File"); + } $zip->close(); } @@ -769,8 +771,8 @@ function replaceNewUpdater() $update->checkConfig(); $update->checkphpmodules(); -} catch (\UpdateException $e) { - throw $e; +} catch (\Exception $e) { + die($e->getMessage()); } /** @@ -779,194 +781,198 @@ function replaceNewUpdater() * */ if (isset($_POST['action'])) { - set_time_limit(0); - - //ensure that $action is integer - - $action = (int)$_POST['action']; - - header('Content-Type: application/json'); - $writeStep = true; - switch ($action) { - case 0: - $statusJson = $update->currentUpdateStep(); - echo json_encode(array('status' => $statusJson, 'autocontinue' => true)); - break; - case 1: - $updateMessage = $update->checkIfThereIsAnUpdate(); - $isThereAnUpdate = $update->availableUpdate(); - if ($isThereAnUpdate === false) { - echo(json_encode(array('continue' => false, 'response' => $updateMessage))); - } else { - echo(json_encode(array('continue' => true, 'response' => $updateMessage))); - } - break; - case 2: - echo(json_encode(array('continue' => true, 'autocontinue' => true, 'response' => 'Starting integrity check'))); - break; - case 3: - $unexpectedFiles = $update->checkRequiredFiles(); - if (count($unexpectedFiles) !== 0) { - $elements = "Error: The following files are either not expected and should be removed, or are missing but required and should be put back in place \n"; - foreach ($unexpectedFiles as $key => $fileName) { - $elements .= $key . "\n"; + try { + set_time_limit(0); + + //ensure that $action is integer + + $action = (int)$_POST['action']; + + header('Content-Type: application/json'); + $writeStep = true; + switch ($action) { + case 0: + $statusJson = $update->currentUpdateStep(); + echo json_encode(array('status' => $statusJson, 'autocontinue' => true)); + break; + case 1: + $updateMessage = $update->checkIfThereIsAnUpdate(); + $isThereAnUpdate = $update->availableUpdate(); + if ($isThereAnUpdate === false) { + echo(json_encode(array('continue' => false, 'response' => $updateMessage))); + } else { + echo(json_encode(array('continue' => true, 'response' => $updateMessage))); } - echo(json_encode(array('retry' => true, 'continue' => false, 'response' => $elements))); - } else { - echo(json_encode(array('continue' => true, 'response' => 'Integrity check successful', 'autocontinue' => true))); - } - break; - case 4: - $notWriteableFiles = $update->checkWritePermissions(); - if (count($notWriteableFiles) !== 0) { - $notWriteableElements = "Error: No write permission for the following files: \n";; - foreach ($notWriteableFiles as $key => $fileName) { - $notWriteableElements .= $fileName . "\n"; + break; + case 2: + echo(json_encode(array('continue' => true, 'autocontinue' => true, 'response' => 'Starting integrity check'))); + break; + case 3: + $unexpectedFiles = $update->checkRequiredFiles(); + if (count($unexpectedFiles) !== 0) { + $elements = "Error: The following files are either not expected and should be removed, or are missing but required and should be put back in place \n"; + foreach ($unexpectedFiles as $key => $fileName) { + $elements .= $key . "\n"; + } + echo(json_encode(array('retry' => true, 'continue' => false, 'response' => $elements))); + } else { + echo(json_encode(array('continue' => true, 'response' => 'Integrity check successful', 'autocontinue' => true))); } - echo(json_encode(array('retry' => true, 'continue' => false, 'response' => $notWriteableElements))); - } else { - echo(json_encode(array('continue' => true, 'response' => 'Write check successful.', 'autocontinue' => true))); - } - break; - case 5: - echo(json_encode(array('continue' => true, 'response' => 'Do you want a backup?
Yes
No
'))); - break; - case 6: - $createBackup = $_POST['create_backup']; - if ($createBackup === 'true') { - echo(json_encode(array('continue' => true, 'response' => 'Choose location where to backup the /lists directory. Please make sure to choose a location outside the web root:
'))); - } else { - echo(json_encode(array('continue' => true, 'response' => '', 'autocontinue' => true))); - } - break; - case 7: - $createBackup = $_POST['create_backup']; - if ($createBackup === 'true') { - $backupLocation = realpath(dirname($_POST['backup_location'])); - $phplistRootFolder = realpath(__DIR__ . '/../../'); - if (strpos($backupLocation, $phplistRootFolder) === 0) { - echo(json_encode(array('retry' => true, 'continue' => false, 'response' => 'Error: Please choose a folder outside of your phpList installation.'))); - break; + break; + case 4: + $notWriteableFiles = $update->checkWritePermissions(); + if (count($notWriteableFiles) !== 0) { + $notWriteableElements = "Error: No write permission for the following files: \n";; + foreach ($notWriteableFiles as $key => $fileName) { + $notWriteableElements .= $fileName . "\n"; + } + echo(json_encode(array('retry' => true, 'continue' => false, 'response' => $notWriteableElements))); + } else { + echo(json_encode(array('continue' => true, 'response' => 'Write check successful.', 'autocontinue' => true))); } - if (!preg_match("/^.*\.(zip)$/i", $_POST['backup_location'])) { - echo(json_encode(array('retry' => true, 'continue' => false, 'response' => 'Error: Please add .zip extension.'))); - break; + break; + case 5: + echo(json_encode(array('continue' => true, 'response' => 'Do you want a backup?
Yes
No
'))); + break; + case 6: + $createBackup = $_POST['create_backup']; + if ($createBackup === 'true') { + echo(json_encode(array('continue' => true, 'response' => 'Choose location where to backup the /lists directory. Please make sure to choose a location outside the web root:
'))); + } else { + echo(json_encode(array('continue' => true, 'response' => '', 'autocontinue' => true))); } + break; + case 7: + $createBackup = $_POST['create_backup']; + if ($createBackup === 'true') { + $backupLocation = realpath(dirname($_POST['backup_location'])); + $phplistRootFolder = realpath(__DIR__ . '/../../'); + if (strpos($backupLocation, $phplistRootFolder) === 0) { + echo(json_encode(array('retry' => true, 'continue' => false, 'response' => 'Error: Please choose a folder outside of your phpList installation.'))); + break; + } + if (!preg_match("/^.*\.(zip)$/i", $_POST['backup_location'])) { + echo(json_encode(array('retry' => true, 'continue' => false, 'response' => 'Error: Please add .zip extension.'))); + break; + } + try { + $update->backUpFiles($_POST['backup_location']); + echo(json_encode(array('continue' => true, 'response' => 'Backup has been created'))); + } catch (\Exception $e) { + echo(json_encode(array('retry' => true, 'continue' => false, 'response' => $e->getMessage()))); + break; + } + } else { + echo(json_encode(array('continue' => true, 'response' => 'No back up created', 'autocontinue' => true))); + } + + break; + case 8: + echo(json_encode(array('continue' => true, 'autocontinue' => true, 'response' => 'Download in progress'))); + break; + case 9: try { - $update->backUpFiles($_POST['backup_location']); - echo(json_encode(array('continue' => true, 'response' => 'Backup has been created'))); + $update->downloadUpdate(); + echo(json_encode(array('continue' => true, 'response' => 'The update has been downloaded!'))); } catch (\Exception $e) { - echo(json_encode(array('retry' => true, 'continue' => false, 'response' => $e->getMessage()))); - break; + echo(json_encode(array('continue' => false, 'response' => $e->getMessage()))); } - } else { - echo(json_encode(array('continue' => true, 'response' => 'No back up created', 'autocontinue' => true))); - } - - break; - case 8: - echo(json_encode(array('continue' => true, 'autocontinue' => true, 'response' => 'Download in progress'))); - break; - case 9: - try { - $update->downloadUpdate(); - echo(json_encode(array('continue' => true, 'response' => 'The update has been downloaded!'))); - } catch (\Exception $e) { - echo(json_encode(array('continue' => false, 'response' => $e->getMessage()))); - } - break; - case 10: - $on = $update->addMaintenanceMode(); - if ($on === false) { - echo(json_encode(array('continue' => false, 'response' => 'Cannot set the maintenance mode on!'))); - } else { - echo(json_encode(array('continue' => true, 'response' => 'Set maintenance mode on', 'autocontinue' => true))); - } - break; - case 11: - try { - $update->replacePHPEntryPoints(); - echo(json_encode(array('continue' => true, 'response' => 'Replaced entry points', 'autocontinue' => true))); - } catch (\Exception $e) { - echo(json_encode(array('continue' => false, 'response' => $e->getMessage()))); - } - break; - case 12: - try { - $update->movePluginsInTempFolder(); - echo(json_encode(array('continue' => true, 'response' => 'Backing up the plugins', 'autocontinue' => true))); - } catch (\Exception $e) { - echo(json_encode(array('continue' => false, 'response' => $e->getMessage()))); - } - break; - case 13: - try { - $update->deleteFiles(); - echo(json_encode(array('continue' => true, 'response' => 'Old files have been deleted!', 'autocontinue' => true))); - } catch (\Exception $e) { - echo(json_encode(array('continue' => false, 'response' => $e->getMessage()))); - } - break; - case 14: - try { - $update->moveNewFiles(); - echo(json_encode(array('continue' => true, 'response' => 'Moved new files in place!', 'autocontinue' => true))); - - } catch (\Exception $e) { - echo(json_encode(array('continue' => false, 'response' => $e->getMessage()))); - } - break; - case 15: - try { - $update->movePluginsInPlace(); - echo(json_encode(array('continue' => true, 'response' => 'Moved plugins in place!', 'autocontinue' => true))); - } catch (\Exception $e) { - echo(json_encode(array('continue' => false, 'response' => $e->getMessage()))); - } - break; - case 16: - try { - $update->moveEntryPHPpoints(); - echo(json_encode(array('continue' => true, 'response' => 'Moved new entry points in place!', 'autocontinue' => true))); - } catch (\Exception $e) { - echo(json_encode(array('continue' => false, 'response' => $e->getMessage()))); - } - break; - case 17: - try { - $update->moveUpdater(); - echo(json_encode(array('continue' => true, 'response' => 'Moved new entry points in place!', 'autocontinue' => true))); - } catch (\Exception $e) { - echo(json_encode(array('continue' => false, 'response' => $e->getMessage()))); - } - break; - case 18: - try { - $update->deleteTemporaryFiles(); - echo(json_encode(array('continue' => true, 'response' => 'Deleted temporary files!', 'autocontinue' => true))); - } catch (\Exception $e) { - echo(json_encode(array('continue' => false, 'response' => $e->getMessage()))); - } - break; - case 19: - try { - $update->removeMaintenanceMode(); - echo(json_encode(array('continue' => true, 'response' => 'Removed maintenance mode', 'autocontinue' => true))); - } catch (\Exception $e) { - echo(json_encode(array('continue' => false, 'response' => $e->getMessage()))); - } - break; - case 20: - $writeStep = false; - try { - $update->replaceNewUpdater(); - $update->deauthUpdaterSession(); - echo(json_encode(array('continue' => true, 'nextUrl' => '../admin/', 'response' => 'Updated successfully.'))); - } catch (\Exception $e) { - echo(json_encode(array('continue' => false, 'response' => $e->getMessage()))); - } - break; - }; + break; + case 10: + $on = $update->addMaintenanceMode(); + if ($on === false) { + echo(json_encode(array('continue' => false, 'response' => 'Cannot set the maintenance mode on!'))); + } else { + echo(json_encode(array('continue' => true, 'response' => 'Set maintenance mode on', 'autocontinue' => true))); + } + break; + case 11: + try { + $update->replacePHPEntryPoints(); + echo(json_encode(array('continue' => true, 'response' => 'Replaced entry points', 'autocontinue' => true))); + } catch (\Exception $e) { + echo(json_encode(array('continue' => false, 'response' => $e->getMessage()))); + } + break; + case 12: + try { + $update->movePluginsInTempFolder(); + echo(json_encode(array('continue' => true, 'response' => 'Backing up the plugins', 'autocontinue' => true))); + } catch (\Exception $e) { + echo(json_encode(array('continue' => false, 'response' => $e->getMessage()))); + } + break; + case 13: + try { + $update->deleteFiles(); + echo(json_encode(array('continue' => true, 'response' => 'Old files have been deleted!', 'autocontinue' => true))); + } catch (\Exception $e) { + echo(json_encode(array('continue' => false, 'response' => $e->getMessage()))); + } + break; + case 14: + try { + $update->moveNewFiles(); + echo(json_encode(array('continue' => true, 'response' => 'Moved new files in place!', 'autocontinue' => true))); + + } catch (\Exception $e) { + echo(json_encode(array('continue' => false, 'response' => $e->getMessage()))); + } + break; + case 15: + try { + $update->movePluginsInPlace(); + echo(json_encode(array('continue' => true, 'response' => 'Moved plugins in place!', 'autocontinue' => true))); + } catch (\Exception $e) { + echo(json_encode(array('continue' => false, 'response' => $e->getMessage()))); + } + break; + case 16: + try { + $update->moveEntryPHPpoints(); + echo(json_encode(array('continue' => true, 'response' => 'Moved new entry points in place!', 'autocontinue' => true))); + } catch (\Exception $e) { + echo(json_encode(array('continue' => false, 'response' => $e->getMessage()))); + } + break; + case 17: + try { + $update->moveUpdater(); + echo(json_encode(array('continue' => true, 'response' => 'Moved new entry points in place!', 'autocontinue' => true))); + } catch (\Exception $e) { + echo(json_encode(array('continue' => false, 'response' => $e->getMessage()))); + } + break; + case 18: + try { + $update->deleteTemporaryFiles(); + echo(json_encode(array('continue' => true, 'response' => 'Deleted temporary files!', 'autocontinue' => true))); + } catch (\Exception $e) { + echo(json_encode(array('continue' => false, 'response' => $e->getMessage()))); + } + break; + case 19: + try { + $update->removeMaintenanceMode(); + echo(json_encode(array('continue' => true, 'response' => 'Removed maintenance mode', 'autocontinue' => true))); + } catch (\Exception $e) { + echo(json_encode(array('continue' => false, 'response' => $e->getMessage()))); + } + break; + case 20: + $writeStep = false; + try { + $update->replaceNewUpdater(); + $update->deauthUpdaterSession(); + echo(json_encode(array('continue' => true, 'nextUrl' => '../admin/', 'response' => 'Updated successfully.'))); + } catch (\Exception $e) { + echo(json_encode(array('continue' => false, 'response' => $e->getMessage()))); + } + break; + } + } catch (\Exception $e) { + echo(json_encode(array('continue' => false, 'response' => 'Error: ' . $e->getMessage()))); + } if ($writeStep) { try {