v-wordpress-plugin-updater/v-update-api/app/Controllers/PluginsController.php
Nikolai X. Shadeauxs 8fc3bc20ad
Some checks failed
CI & Security / CI Scan (push) Failing after 9s
CI & Security / CodeQL (JavaScript) (push) Failing after 6s
CI & Security / Semgrep (PHP) (push) Failing after 8s
modified: .github/copilot-instructions.md
modified:   CHANGELOG.md
	modified:   README.md
2026-04-06 14:39:21 -04:00

156 lines
5.5 KiB
PHP

<?php
// phpcs:ignoreFile PSR1.Files.SideEffects.FoundWithSymbols
/**
* Project: UpdateAPI
* Author: Vontainment <services@vontainment.com>
* License: https://opensource.org/licenses/MIT MIT License
* Link: https://vontainment.com
* Version: 4.5.0
*
* File: PluginsController.php
* Description: WordPress Update API
*/
namespace App\Controllers;
use App\Helpers\ValidationHelper;
use App\Core\ErrorManager;
use App\Models\PluginModel;
use App\Helpers\MessageHelper;
use App\Helpers\SessionHelper;
use App\Core\Response;
class PluginsController
{
/**
* Handles GET requests for plugin-related actions.
*
* @return Response
*/
public function handleRequest(): Response
{
$pluginsTableHtml = $this->getPluginsTableHtml();
return Response::view('plupdate', [
'pluginsTableHtml' => $pluginsTableHtml,
]);
}
/**
* Handles POST submissions for plugin-related actions.
*
* @return Response
*/
public function handleSubmission(): Response
{
$token = $_POST['csrf_token'] ?? '';
if (!ValidationHelper::validateCsrfToken($token)) {
$error = 'Invalid Form Action.';
ErrorManager::log($error);
$isAjax = !empty($_SERVER['HTTP_X_REQUESTED_WITH']) &&
strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) === 'xmlhttprequest';
if ($isAjax) {
return Response::text($error, 400);
}
MessageHelper::addMessage($error);
return Response::redirect('/plupdate');
}
$isAjax = !empty($_SERVER['HTTP_X_REQUESTED_WITH']) &&
strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) === 'xmlhttprequest';
if (isset($_FILES['plugin_file'])) {
$messages = PluginModel::uploadFiles($_FILES['plugin_file'], $isAjax);
if ($isAjax) {
return Response::text(implode("\n", $messages));
}
foreach ($messages as $message) {
MessageHelper::addMessage($message);
}
return Response::redirect('/plupdate');
} elseif (isset($_POST['delete_plugin'])) {
$pluginName = isset($_POST['plugin_name'])
? ValidationHelper::validateSlug($_POST['plugin_name'])
: null;
if ($pluginName !== null && PluginModel::deletePlugin($pluginName)) {
MessageHelper::addMessage('Plugin deleted successfully!');
} else {
$error = 'Failed to delete plugin file. Please try again.';
ErrorManager::log($error);
MessageHelper::addMessage($error);
}
return Response::redirect('/plupdate');
}
return Response::redirect('/plupdate');
}
/**
* Generates an HTML table row for a plugin.
* @param array{slug: string, version: string} $pluginName
*/
private function generatePluginTableRow(array $pluginName): string
{
$name = str_replace(['-', '_'], ' ', $pluginName['slug']);
$version = $pluginName['version'];
$pluginFile = $pluginName['slug'] . '_' . $version . '.zip';
$csrfToken = SessionHelper::get('csrf_token') ?? '';
return '<tr>
<td>' . htmlspecialchars($name, ENT_QUOTES, 'UTF-8') . '</td>
<td>' . htmlspecialchars($version, ENT_QUOTES, 'UTF-8') . '</td>
<td>
<form method="POST" action="/plupdate" class="inline-action-form">
<input type="hidden" name="csrf_token" value="' .
htmlspecialchars((string) $csrfToken, ENT_QUOTES, 'UTF-8') . '">
<input type="hidden" name="plugin_name" value="' .
htmlspecialchars($pluginFile, ENT_QUOTES, 'UTF-8') . '">
<button class="pl-submit red-button" type="submit" name="delete_plugin">Delete</button>
</form>
</td>
</tr>';
}
/**
* Generates the plugins table HTML for display.
*
* @return string HTML table or message.
*/
private function getPluginsTableHtml(): string
{
$plugins = PluginModel::getPlugins();
if (count($plugins) > 0) {
$halfCount = (int) ceil(count($plugins) / 2);
$pluginsColumn1 = array_slice($plugins, 0, $halfCount);
$pluginsColumn2 = array_slice($plugins, $halfCount);
$pluginsTableHtml = '<div class="row"><div class="column">
<table>
<thead>
<tr>
<th>Name</th>
<th>Version</th>
<th>Action</th>
</tr>
</thead>
<tbody>';
foreach ($pluginsColumn1 as $plugin) {
$pluginsTableHtml .= $this->generatePluginTableRow($plugin);
}
$pluginsTableHtml .= '</tbody></table></div><div class="column"><table>
<thead>
<tr>
<th>Name</th>
<th>Version</th>
<th>Action</th>
</tr>
</thead>
<tbody>';
foreach ($pluginsColumn2 as $plugin) {
$pluginsTableHtml .= $this->generatePluginTableRow($plugin);
}
$pluginsTableHtml .= '</tbody></table></div></div>';
} else {
$pluginsTableHtml = "No plugins found.";
}
return $pluginsTableHtml;
}
}