20 const API_KEY =
'4abe15e5-95f2-4663-ad12-eadb245b28b4';
21 const API_URL =
'https://bearsampp.com/index.php?option=com_osmembership&task=api.get_active_plan_ids&api_key=';
24 const JSON_URL =
'https://raw.githubusercontent.com/Bearsampp/Bearsampp/main/core/resources/quickpick-releases.json';
36 'Adminer' => [
'type' =>
'application'],
37 'Apache' => [
'type' =>
'binary'],
38 'Composer' => [
'type' =>
'tools'],
39 'ConsoleZ' => [
'type' =>
'tools'],
40 'Ghostscript' => [
'type' =>
'tools'],
41 'Git' => [
'type' =>
'tools'],
42 'Mailpit' => [
'type' =>
'binary'],
43 'MariaDB' => [
'type' =>
'binary'],
44 'Memcached' => [
'type' =>
'binary'],
45 'MySQL' => [
'type' =>
'binary'],
46 'Ngrok' => [
'type' =>
'tools'],
47 'NodeJS' => [
'type' =>
'binary'],
48 'Perl' => [
'type' =>
'tools'],
49 'PHP' => [
'type' =>
'binary'],
50 'PhpMyAdmin' => [
'type' =>
'application'],
51 'PhpPgAdmin' => [
'type' =>
'application'],
52 'PostgreSQL' => [
'type' =>
'binary'],
53 'Python' => [
'type' =>
'tools'],
54 'Ruby' => [
'type' =>
'tools'],
55 'Webgrind' => [
'type' =>
'application'],
56 'Xlight' => [
'type' =>
'binary'],
57 'Yarn' => [
'type' =>
'tools']
80 $this->jsonFilePath =
$bearsamppCore->getResourcesPath() .
'/quickpick-releases.json';
90 return array_keys( $this->modules );
126 $localFileCreationTime = 0;
129 if ( file_exists( $this->jsonFilePath ) ) {
130 $localFileCreationTime = filectime( $this->jsonFilePath );
137 $headers = get_headers( self::JSON_URL, 1 );
138 if ( $headers ===
false || !isset( $headers[
'Last-Modified'] ) ) {
142 $remoteFileCreationTime = strtotime( $headers[
'Last-Modified'] );
145 if ( $remoteFileCreationTime > $localFileCreationTime || $localFileCreationTime === 0 ) {
160 $content = @file_get_contents( $this->jsonFilePath );
161 if ( $content ===
false ) {
162 Util::logError(
'Error fetching content from JSON file: ' . $this->jsonFilePath );
164 return [
'error' =>
'Error fetching JSON file'];
167 $data = json_decode( $content,
true );
168 if ( json_last_error() !== JSON_ERROR_NONE ) {
169 Util::logError(
'Error decoding JSON content: ' . json_last_error_msg() );
171 return [
'error' =>
'Error decoding JSON content'];
191 $jsonContent = file_get_contents( $url );
193 if ( $jsonContent ===
false ) {
195 throw new Exception(
'Failed to fetch JSON content from the URL.' );
199 $result = file_put_contents( $this->jsonFilePath, $jsonContent );
203 throw new Exception(
'Failed to save JSON content to the specified path.' );
207 return [
'success' =>
'JSON content fetched and saved successfully'];
226 foreach ( $jsonData as $entry ) {
227 if ( is_array( $entry ) ) {
228 if ( isset( $entry[
'module'] ) && is_string( $entry[
'module'] ) ) {
229 if ( isset( $entry[
'versions'] ) && is_array( $entry[
'versions'] ) ) {
230 $versions[$entry[
'module']] = array_column( $entry[
'versions'],
null,
'version' );
242 return [
'error' =>
'No versions found'];
266 Util::logDebug(
'getModuleUrl called for module: ' . $module .
' version: ' . $version );
267 $url = trim( $this->versions[
'module-' . strtolower( $module )][$version][
'url'] );
269 Util::logDebug(
'Found URL for version: ' . $version .
' URL: ' . $url );
276 return [
'error' =>
'Version not found'];
312 if ( empty( $DownloadId ) ) {
318 $url = self::API_URL . self::API_KEY .
'&download_id=' . $DownloadId;
325 $error = error_get_last();
326 Util::logError(
'Error fetching API response: ' . $error[
'message'] );
336 if ( json_last_error() !== JSON_ERROR_NONE ) {
337 Util::logError(
'Error decoding JSON response: ' . json_last_error_msg() );
343 if ( isset( $data[
'success'] ) && $data[
'success'] ===
true && isset( $data[
'data'] ) && is_array( $data[
'data'] ) && count( $data[
'data'] ) > 0 ) {
373 if ( is_array( $moduleUrl ) && isset( $moduleUrl[
'error'] ) ) {
374 Util::logError(
'Module URL not found for module: ' . $module .
' version: ' . $version );
376 return [
'error' =>
'Module URL not found'];
379 if ( empty( $moduleUrl ) ) {
380 Util::logError(
'Module URL not found for module: ' . $module .
' version: ' . $version );
382 return [
'error' =>
'Module URL not found'];
395 return [
'error' =>
'No internet connection'];
415 $fileName = basename( $moduleUrl );
418 $tmpFilePath = $tmpDir .
'/' . $fileName;
421 $moduleName = str_replace(
'module-',
'', $module );
424 $moduleType = $this->modules[$module][
'type'];
437 Util::logError(
'Failed to retrieve file from URL: ' . $moduleUrl );
439 return [
'error' =>
'Failed to retrieve file from URL'];
443 $fileExtension = pathinfo( $tmpFilePath, PATHINFO_EXTENSION );
446 if ( $fileExtension ===
'7z' || $fileExtension ===
'zip' ) {
448 echo json_encode( [
'phase' =>
'extracting'] );
449 if ( ob_get_length() ) {
454 $unzipResult =
$bearsamppCore->unzipFile( $tmpFilePath, $destination,
function ($currentFile, $totalFiles) {
455 echo json_encode( [
'progress' =>
"$currentFile of $totalFiles"] );
456 if ( ob_get_length() ) {
462 if ( $unzipResult ===
false ) {
463 return [
'error' =>
'Failed to unzip file. File: ' . $tmpFilePath .
' could not be unzipped',
'Destination: ' . $destination];
467 Util::logError(
'Unsupported file extension: ' . $fileExtension );
469 return [
'error' =>
'Unsupported file extension'];
472 return [
'success' =>
'Module installed successfully'];
490 if ( $moduleType ===
'application' ) {
491 $destination =
$bearsamppRoot->getAppsPath() .
'/' . strtolower( $moduleName ) .
'/';
493 elseif ( $moduleType ===
'binary' ) {
494 $destination =
$bearsamppRoot->getBinPath() .
'/' . strtolower( $moduleName ) .
'/';
496 elseif ( $moduleType ===
'tools' ) {
497 $destination =
$bearsamppRoot->getToolsPath() .
'/' . strtolower( $moduleName ) .
'/';
527 <div
id =
'quickPickContainer'>
528 <div
class = 'quickpick me-5'>
530 <div class =
"custom-select">
531 <button
class = "select-button
" role = "combobox
"
532 aria-label = "select button
"
533 aria-haspopup = "listbox
"
534 aria-expanded = "false
"
535 aria-controls = "select-dropdown
">
536 <span class = "selected-value
">Select a module and version</span>
537 <span class = "arrow
"></span>
539 <ul class = "select-dropdown
" role = "listbox
" id = "select-dropdown
">
542 foreach ( $modules as $module ): ?>
543 <?php if ( is_string( $module ) ): ?>
544 <li role = "option
" class = "moduleheader
">
545 <?php echo htmlspecialchars( $module ); ?>
549 foreach ( $versions['module-' . strtolower( $module )] as $version_array ): ?>
550 <li role = "option
" class = "moduleoption
"
551 id = "<?php echo htmlspecialchars( $module ); ?>-version-<?php echo htmlspecialchars( $version_array[
'version'] ); ?>-li
">
552 <input type = "radio
"
553 id = "<?php echo htmlspecialchars( $module ); ?>-version-<?php echo htmlspecialchars( $version_array[
'version'] ); ?>
"
554 name = "module
" data-module = "<?php echo htmlspecialchars( $module ); ?>
"
555 data-value = "<?php echo htmlspecialchars( $version_array[
'version'] ); ?>
">
557 for = "<?php echo htmlspecialchars( $module ); ?>-version-<?php echo htmlspecialchars( $version_array[
'version'] ); ?>
"><?php echo htmlspecialchars( $version_array['version'] ); ?></label>
565 <div class = "progress
" id = "progress
" tabindex = "-1
" style = "width:260px;display:none
"
566 aria-labelledby = "progressbar
" aria-hidden = "true">
567 <div class = "progress-bar progress-bar-striped progress-bar-animated
" id = "progress-bar
" role = "progressbar
" aria-valuenow = "0
" aria-valuemin = "0
"
568 aria-valuemax = "100
" data-module = "Module"
569 data-version = "0.0.0
">0%
571 <div id = "download-module
" style = "display: none
">ModuleName</div>
572 <div id = "download-version
" style = "display: none
">Version</div>
576 <div id = "subscribeContainer
" class = "text-center mt-3 pe-3
">
577 <a href = "<?php echo
Util::getWebsiteUrl(
'subscribe' ); ?>
" class = "btn btn-dark d-
inline-flex align-items-center
">
578 <img src = "<?php echo
$imagesPath .
'subscribe.svg'; ?>
" alt = "Subscribe Icon
" class = "me-2
">
579 Subscribe to QuickPick now
586 <div id = "InternetState
" class = "text-center mt-3 pe-3
">
587 <img src = "<?php echo
$imagesPath .
'no-wifi-icon.svg'; ?>
" alt = "No Wifi Icon
" class = "me-2
">
588 <span>No internet present</span>
593 return ob_get_clean();
getQuickpickMenu(array $modules, array $versions, string $imagesPath)
getModuleDestinationPath(string $moduleType, string $moduleName)
fetchAndUnzipModule(string $moduleUrl, string $module)
installModule(string $module, string $version)
loadQuickpick(string $imagesPath)
getModuleUrl(string $module, string $version)
static logError($data, $file=null)
static getWebsiteUrl($path='', $fragment='', $utmSource=true)
static logDebug($data, $file=null)
static checkInternetState()