30 'Apache' => [
'type' =>
'binary'],
31 'Bruno' => [
'type' =>
'tools'],
32 'Composer' => [
'type' =>
'tools'],
33 'ConsoleZ' => [
'type' =>
'tools'],
34 'Ghostscript' => [
'type' =>
'tools'],
35 'Git' => [
'type' =>
'tools'],
36 'Mailpit' => [
'type' =>
'binary'],
37 'MariaDB' => [
'type' =>
'binary'],
38 'Memcached' => [
'type' =>
'binary'],
39 'MySQL' => [
'type' =>
'binary'],
40 'Ngrok' => [
'type' =>
'tools'],
41 'NodeJS' => [
'type' =>
'binary'],
42 'Perl' => [
'type' =>
'tools'],
43 'PHP' => [
'type' =>
'binary'],
44 'PhpMyAdmin' => [
'type' =>
'application'],
45 'PhpPgAdmin' => [
'type' =>
'application'],
46 'PostgreSQL' => [
'type' =>
'binary'],
47 'Python' => [
'type' =>
'tools'],
48 'Ruby' => [
'type' =>
'tools'],
49 'Xlight' => [
'type' =>
'binary']
72 $this->jsonFilePath =
$bearsamppCore->getResourcesPath() .
'/quickpick-releases.json';
86 if ($isPrerelease && $includePr == 1) {
87 return '<span class="text-danger">' . htmlspecialchars($version) .
' PR</span>';
90 return htmlspecialchars($version);
100 return array_keys( $this->modules );
151 $remoteFileCreationTime = strtotime(isset($headers[
'Date']) ? $headers[
'Date'] :
'');
165 if (!file_exists($this->jsonFilePath)) {
170 return filectime($this->jsonFilePath);
182 if ($headers ===
false || !isset($headers[
'Date'])) {
209 $content = @file_get_contents( $this->jsonFilePath );
210 if ( $content ===
false ) {
211 Util::logError(
'Error fetching content from JSON file: ' . $this->jsonFilePath );
213 return [
'error' =>
'Error fetching JSON file'];
216 $data = json_decode( $content,
true );
217 if ( json_last_error() !== JSON_ERROR_NONE ) {
218 Util::logError(
'Error decoding JSON content: ' . json_last_error_msg() );
220 return [
'error' =>
'Error decoding JSON content'];
239 if ( $jsonContent ===
false ) {
241 throw new Exception(
'Failed to fetch JSON content from the URL.' );
245 $result = file_put_contents( $this->jsonFilePath, $jsonContent );
249 throw new Exception(
'Failed to save JSON content to the specified path.' );
253 return [
'success' =>
'JSON content fetched and saved successfully'];
272 foreach ( $jsonData as $entry ) {
273 if ( is_array( $entry ) ) {
274 if ( isset( $entry[
'module'] ) && is_string( $entry[
'module'] ) ) {
275 if ( isset( $entry[
'versions'] ) && is_array( $entry[
'versions'] ) ) {
276 $versions[$entry[
'module']] = array_column( $entry[
'versions'],
null,
'version' );
288 return [
'error' =>
'No versions found'];
312 Util::logDebug(
'getModuleUrl called for module: ' . $module .
' version: ' . $version );
313 $url = trim( $this->versions[
'module-' . strtolower( $module )][$version][
'url'] );
315 Util::logDebug(
'Found URL for version: ' . $version .
' URL: ' . $url );
322 return [
'error' =>
'Version not found'];
358 if ( empty( $DownloadId ) ) {
371 $error = error_get_last();
372 Util::logError(
'Error fetching API response: ' . $error[
'message'] );
382 if ( json_last_error() !== JSON_ERROR_NONE ) {
383 Util::logError(
'Error decoding JSON response: ' . json_last_error_msg() );
389 if ( isset( $data[
'success'] ) && $data[
'success'] ===
true && isset( $data[
'data'] ) && is_array( $data[
'data'] ) && count( $data[
'data'] ) > 0 ) {
419 if ( is_array( $moduleUrl ) && isset( $moduleUrl[
'error'] ) ) {
420 Util::logError(
'Module URL not found for module: ' . $module .
' version: ' . $version );
422 return [
'error' =>
'Module URL not found'];
425 if ( empty( $moduleUrl ) ) {
426 Util::logError(
'Module URL not found for module: ' . $module .
' version: ' . $version );
428 return [
'error' =>
'Module URL not found'];
441 return [
'error' =>
'No internet connection'];
461 $fileName = basename($moduleUrl);
464 $tmpFilePath = $tmpDir .
'/' . $fileName;
467 $moduleName = str_replace(
'module-',
'', $module);
470 $moduleType = $this->modules[$module][
'type'];
483 Util::logError(
'Failed to retrieve file from URL: ' . $moduleUrl);
484 return [
'error' =>
'Failed to retrieve file from URL'];
488 $fileExtension = pathinfo($tmpFilePath, PATHINFO_EXTENSION);
491 if ($fileExtension ===
'7z' || $fileExtension ===
'zip') {
493 echo json_encode([
'phase' =>
'extracting']);
494 if (ob_get_length()) {
499 $unzipResult =
$bearsamppCore->unzipFile($tmpFilePath, $destination,
function ($currentPercentage) {
500 echo json_encode([
'progress' =>
"$currentPercentage%"]);
501 if (ob_get_length()) {
507 if ($unzipResult ===
false) {
508 return [
'error' =>
'Failed to unzip file. File: ' . $tmpFilePath .
' could not be unzipped',
'Destination: ' . $destination];
512 return [
'error' =>
'Unsupported file extension'];
515 return [
'success' =>
'Module installed successfully'];
533 if ( $moduleType ===
'application' ) {
534 $destination =
$bearsamppRoot->getAppsPath() .
'/' . strtolower( $moduleName ) .
'/';
536 elseif ( $moduleType ===
'binary' ) {
537 $destination =
$bearsamppRoot->getBinPath() .
'/' . strtolower( $moduleName ) .
'/';
539 elseif ( $moduleType ===
'tools' ) {
540 $destination =
$bearsamppRoot->getToolsPath() .
'/' . strtolower( $moduleName ) .
'/';
573 <div
id =
'quickPickContainer'>
574 <div
class = 'quickpick me-5'>
576 <div class =
"custom-select">
577 <button
class = "select-button
" role = "combobox
"
578 aria-label = "select button
"
579 aria-haspopup = "listbox
"
580 aria-expanded = "false
"
581 aria-controls = "select-dropdown
">
582 <span class = "selected-value
">Select a module and version</span>
583 <span class = "arrow
"></span>
585 <ul class = "select-dropdown
" role = "listbox
" id = "select-dropdown
">
588 foreach ( $modules as $module ): ?>
589 <?php if ( is_string( $module ) ): ?>
590 <li role = "option
" class = "moduleheader
">
591 <?php echo htmlspecialchars( $module ); ?>
595 foreach ( $versions['module-' . strtolower( $module )] as $version_array ):
596 // Skip prerelease versions if includePr is not enabled
597 if (isset($version_array['prerelease']) && $version_array['prerelease'] === true && $includePr != 1) {
601 <li role = "option
" class = "moduleoption
"
602 id = "<?php echo htmlspecialchars( $module ); ?>-version-<?php echo htmlspecialchars( $version_array[
'version'] ); ?>-li
">
603 <input type = "radio
"
604 id = "<?php echo htmlspecialchars( $module ); ?>-version-<?php echo htmlspecialchars( $version_array[
'version'] ); ?>
"
605 name = "module
" data-module = "<?php echo htmlspecialchars( $module ); ?>
"
606 data-value = "<?php echo htmlspecialchars( $version_array[
'version'] ); ?>
">
608 for = "<?php echo htmlspecialchars( $module ); ?>-version-<?php echo htmlspecialchars( $version_array[
'version'] ); ?>
"><?php echo $this->formatVersionLabel( $version_array['version'], isset($version_array['prerelease']) && $version_array['prerelease'] === true ); ?></label>
616 <div class = "progress
" id = "progress
" tabindex = "-1
" style = "width:260px;display:none
"
617 aria-labelledby = "progressbar
" aria-hidden = "true">
618 <div class = "progress-bar progress-bar-striped progress-bar-animated
" id = "progress-bar
" role = "progressbar
" aria-valuenow = "0
" aria-valuemin = "0
"
619 aria-valuemax = "100
" data-module = "Module"
620 data-version = "0.0.0
">0%
622 <div id = "download-module
" style = "display: none
">ModuleName</div>
623 <div id = "download-version
" style = "display: none
">Version</div>
627 <div id = "subscribeContainer
" class = "text-center mt-3 pe-3
">
628 <a href = "<?php echo
Util::getWebsiteUrl(
'subscribe' ); ?>
" class = "btn btn-dark d-
inline-flex align-items-center
">
629 <img src = "<?php echo
$imagesPath .
'subscribe.svg'; ?>
" alt = "Subscribe Icon
" class = "me-2
">
630 Subscribe to QuickPick now
637 <div id = "InternetState
" class = "text-center mt-3 pe-3
">
638 <img src = "<?php echo
$imagesPath .
'no-wifi-icon.svg'; ?>
" alt = "No Wifi Icon
" class = "me-2
">
639 <span>No internet present</span>
644 return ob_get_clean();
isValidHeaderResponse($headers)
fetchAndUnzipModule(string $moduleUrl, string $module)
getModuleUrl(string $module, string $version)
getLocalFileCreationTime()
installModule(string $module, string $version)
getModuleDestinationPath(string $moduleType, string $moduleName)
getQuickpickMenu(array $modules, array $versions, string $imagesPath)
formatVersionLabel($version, $isPrerelease=false)
logHeaders(array $headers)
loadQuickpick(string $imagesPath)
static logError($data, $file=null)
static logDebug($data, $file=null)
static getWebsiteUrl($path='', $fragment='', $utmSource=true)
static checkInternetState()