<?php
define('AGENT_NOT_HEARD_PATH', '/parablu/reports/');
define('OVERVIEW_REPORT_PATH', '/parablu/bkpOverview/');
$allowedFunctions = ['moveForView', 'deleteRedundantFile', 'uploadFileSync', 'uploadFolderSync', 'getEmailAddress', 'getAccessTokenGoogle', 'getAccessToken', 'getAccessTokenBilling', 'getAccessTokenAdminConsent', 'uploadAgent', 'uploadLicenseKey', 'uploadInfectedFile', 'downloadReport', 'downloadAgent', 'downloadUsersToExcel', 'downloadSoftDeletedUsersToExcel', 'downloadFailedAssetsDump', 'downloadFailedUsersDump', 'downloadBulkCreateUsersSample', 'downloadBlockUnblockDeleteUsersSample', 'downloadOdbExcelSample', 'downloadSitesToExcel', 'downloadAssetsToExcel', 'downloadServersToExcel', 'downloadBlockUnblockAssetsSample', 'downloadBlockUnblockSitesSample', 'downloadSharepointPolicyPdf', 'downloadOnedrivePolicyFilePdf', 'downloadExchangePolicyFilePdf', 'downloadPolicyFilePdf', 'downloadPolicyFailDump', 'downloadSimpleBulkPolicyMappingSample', 'downloadAdvancedBulkPolicyMappingSample', 'downloadDumpBulkPolicyMapping', 'downloadExportUnusualActivityHistoryToExcel', 'downloadExportActivityHistoryToExcel', 'downloadUserMigrationExcel', 'downloadLog', 'downloadUserMigrationSample', 'uploadLoginLogo', 'uploadHeaderLogo', 'uploadDisclaimer', 'uploadCustomEmail', 'uploadGettingStarted', 'downloadFailedFiles'];
function moveForView($filePath, $ext) {
  $destinationPath = '/var/www/portal/assets/document/';
  $fileName = basename($filePath);
  $newFileName = pathinfo($fileName, PATHINFO_FILENAME) . '.' . $ext;
  $newFilePath = $destinationPath . $newFileName;
  // Debugging output
  echo "Current working directory: " . getcwd() . PHP_EOL;
  echo "Checking file path: '$filePath'" . PHP_EOL;
  // Empty the destination directory
  if (is_dir($destinationPath)) {
    $files = scandir($destinationPath);
    foreach ($files as $file) {
        if ($file !== '.' && $file !== '..') {
            $fileToDelete = $destinationPath . $file;
            if (is_file($fileToDelete)) {
                unlink($fileToDelete);
            }
        }
    }
  } else {
    echo "Error: Destination directory does not exist: $destinationPath";
    return;
  }
  // Trim and resolve real path
  $filePath = trim($filePath);
  $realFilePath = realpath($filePath);
  if (!$realFilePath) {
      // Additional checks if `realpath()` fails
      echo "Error: Unable to resolve the file path." . PHP_EOL;
      if (!file_exists($filePath)) {
          echo "Reason: File does not exist at the provided path: $filePath" . PHP_EOL;
      } else {
          echo "Reason: File exists but could not resolve the real path. Possible reasons:" . PHP_EOL;
          echo "- Hidden characters in the path." . PHP_EOL;
          echo "- Permissions issues preventing access to the file." . PHP_EOL;
          echo "- File path is a broken symbolic link." . PHP_EOL;
      }
      return;
  }
  if (!is_dir($destinationPath)) {
      echo "Error: Destination directory does not exist: $destinationPath";
      return;
  }
  if (!is_writable($destinationPath)) {
      echo "Error: Destination directory is not writable: $destinationPath";
      return;
  }
  $command = "cp " . escapeshellarg($realFilePath) . " " . escapeshellarg($newFilePath);
  $output = shell_exec($command);
  if (!file_exists($newFilePath)) {
      echo "Error: Failed to copy file. Command output: $output";
      return;
  }
  echo "File successfully copied to $newFilePath";
}
function deleteRedundantFile() {
  $destinationPath = '/var/www/portal/assets/document/';
  if (is_dir($destinationPath)) {
    $files = scandir($destinationPath);
    foreach ($files as $file) {
        if ($file !== '.' && $file !== '..') {
            $fileToDelete = $destinationPath . $file;
            if (is_file($fileToDelete)) {
                unlink($fileToDelete);
            }
        }
    }
  } else {
    echo "Error: Destination directory does not exist: $destinationPath";
    return;
  }
}
function uploadFileSync($cloudName, $directoryName) {
  $basePath = "/parablu/".$cloudName."/sync-upload/Portal/";
  $path = $basePath . $directoryName . "/";
  if (!is_dir($path)) {
      if (!mkdir($path, 0777, true)) {
          $result = array(
              'result' => 'fail',
              'msg' => 'Failed to create directory'
          );
          die(json_encode($result));
      }
  }
  $fileName = $_POST['fileName'];
  $chunkIndex = intval($_POST['chunkIndex']);
  $totalChunks = intval($_POST['totalChunks']);
  $fileTmp = $_FILES['file']['tmp_name'];
  $targetFile = $path . $fileName . ".part" . $chunkIndex;
  if (move_uploaded_file($fileTmp, $targetFile)) {
      chmod($targetFile, 0777);
      // If all chunks are uploaded, merge them
      if ($chunkIndex === $totalChunks - 1) {
          $finalFile = $path . $fileName;
          $out = fopen($finalFile, 'wb');
          for ($i = 0; $i < $totalChunks; $i++) {
              $chunkFile = $path . $fileName . ".part" . $i;
              if (!file_exists($chunkFile)) {
                  $result = array(
                      'result' => 'fail',
                      'msg' => 'Missing chunk ' . $i
                  );
                  die(json_encode($result));
              }
              $in = fopen($chunkFile, 'rb');
              while ($buffer = fread($in, 8192)) {
                  fwrite($out, $buffer);
              }
              fclose($in);
              unlink($chunkFile); // Clean up chunk after merging
          }
          fclose($out);
          chmod($finalFile, 0777);
          $response = array(
              'result' => 'success',
              'msg' => 'File uploaded and merged successfully'
          );
          echo json_encode($response);
          exit;
      } else {
          $response = array(
              'result' => 'success',
              'msg' => "Chunk $chunkIndex uploaded successfully"
          );
          echo json_encode($response);
          exit;
      }
  } else {
      $response = array(
          'result' => 'fail',
          'msg' => 'Failed to upload chunk'
      );
      echo json_encode($response);
      exit;
  }
}
function uploadFolderSync() {
  $basePath = "/parablu/bluvaultnew/sync-upload/Portal/";
  $directoryName = "YWRtaW4=";
  $path = $basePath . $directoryName . "/";
  if (!is_dir($path)) {
      if (!mkdir($path, 0777, true)) {
          $result = array(
              'result' => 'fail',
              'msg' => 'Failed to create directory'
          );
          die(json_encode($result));
      }
  }
  $fileName = $_POST['fileName'];
  $chunkIndex = intval($_POST['chunkIndex']);
  $totalChunks = intval($_POST['totalChunks']);
  $fileTmp = $_FILES['file']['tmp_name'];
  $targetFile = $path . $fileName . ".part" . $chunkIndex;
  if (move_uploaded_file($fileTmp, $targetFile)) {
      chmod($targetFile, 0777);
      // If all chunks are uploaded, merge them
      if ($chunkIndex === $totalChunks - 1) {
          $finalFile = $path . $fileName;
          $out = fopen($finalFile, 'wb');
          for ($i = 0; $i < $totalChunks; $i++) {
              $chunkFile = $path . $fileName . ".part" . $i;
              if (!file_exists($chunkFile)) {
                  $result = array(
                      'result' => 'fail',
                      'msg' => 'Missing chunk ' . $i
                  );
                  die(json_encode($result));
              }
              $in = fopen($chunkFile, 'rb');
              while ($buffer = fread($in, 8192)) {
                  fwrite($out, $buffer);
              }
              fclose($in);
              unlink($chunkFile); // Clean up chunk after merging
          }
          fclose($out);
          chmod($finalFile, 0777);
          $response = array(
              'result' => 'success',
              'msg' => 'File uploaded and merged successfully'
          );
          echo json_encode($response);
          exit;
      } else {
          $response = array(
              'result' => 'success',
              'msg' => "Chunk $chunkIndex uploaded successfully"
          );
          echo json_encode($response);
          exit;
      }
  } else {
      $response = array(
          'result' => 'fail',
          'msg' => 'Failed to upload chunk'
      );
      echo json_encode($response);
      exit;
  }
}
function getEmailAddress($token){
  $url = 'https://people.googleapis.com/v1/people/me?personFields=emailAddresses&access_token='.$token;
  $headers = [
        'Content-Type: application/x-www-form-urlencoded',
        'Cache-Control: no-cache',
        'Pragma: no-cache'
    ];
  $ch = curl_init($url);
  curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  curl_setopt($ch, CURLOPT_POST, true);
  curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
  curl_setopt($ch, CURLOPT_FRESH_CONNECT, true);
  curl_setopt($ch, CURLOPT_FORBID_REUSE, true);
  $response = curl_exec($ch);
  $responseData = json_decode($response, true);
  $userEmail = json_encode($responseData['emailAddresses'][0]['value']);
  echo "res : ".json_encode($responseData['emailAddresses'][0]['value']);
  //$emailAddress = $responseData['id_token'];
  return $userEmail;
  }
function getAccessTokenGoogle($cId, $rUri, $cSec, $code, $returnUrl) {
  $url = 'https://accounts.google.com/o/oauth2/token';
$headers = [
        'Content-Type: application/x-www-form-urlencoded',
        'Cache-Control: no-cache',
        'Pragma: no-cache'
    ];
$body = http_build_query([
  'client_id' => $cId,
  'redirect_uri' => $rUri,
  'client_secret' => $cSec,
  'code' => $code,
  'grant_type' => 'authorization_code'
]);
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
curl_setopt($ch, CURLOPT_FRESH_CONNECT, true);
curl_setopt($ch, CURLOPT_FORBID_REUSE, true);
$response = curl_exec($ch);
$responseData = json_decode($response, true);
echo "<script>
    console.log('OAuth2 Token Exchange');
    console.log('Request URL:', '" . $url . "');
    console.log('Request Headers:', " . json_encode($headers) . ");
    console.log('Request Body (string):', `" . addslashes($body) . "`);
    console.log('Raw API Response:', " . json_encode($responseData) . ");
    </script>";
if (isset($responseData['access_token']) && isset($responseData['refresh_token']) && isset($responseData['id_token'])) {
$accessToken = $responseData['access_token'];
$refreshToken = $responseData['refresh_token'];
$authToken = $responseData['id_token'];

echo "<script>
    localStorage.setItem('access_token', '$accessToken');
    localStorage.setItem('refresh_token', '$refreshToken');
    localStorage.setItem('auth_token', '$authToken');
    window.location.href = decodeURIComponent('$returnUrl');
  </script>
";
} else {
echo "
  <script>
      window.opener.postMessage({ error: 'Failed to get access token or refresh token' }, '*');
      window.location.href = '$returnUrl';
  </script>
";
}
curl_close($ch);
}
function getAccessToken($cId, $rUri, $cSec, $code, $returnUrl) {
        $url = 'https://login.microsoftonline.com/common/oauth2/token';
    $headers = [
        'Content-Type: application/x-www-form-urlencoded',
        'Cache-Control: no-cache',
        'Pragma: no-cache'
    ];
    $body = http_build_query([
        'client_id' => $cId,
        'redirect_uri' => $rUri,
        'client_secret' => $cSec,
        'code' => $code,
        'grant_type' => 'authorization_code',
        'resource' => 'https://graph.microsoft.com/'
    ]);
    $ch = curl_init($url);
    curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
    curl_setopt($ch, CURLOPT_FRESH_CONNECT, true);
    curl_setopt($ch, CURLOPT_FORBID_REUSE, true);
    $response = curl_exec($ch);
    $responseData = json_decode($response, true);
    echo "<script>
    console.log('OAuth2 Token Exchange');
    console.log('Request URL:', '" . $url . "');
    console.log('Request Headers:', " . json_encode($headers) . ");
    console.log('Request Body (string):', `" . addslashes($body) . "`);
    console.log('Raw API Response:', " . json_encode($responseData) . ");
    </script>";
    if (isset($responseData['access_token']) && isset($responseData['refresh_token'])) {
    $accessToken = $responseData['access_token'];
    $refreshToken = $responseData['refresh_token'];

    echo "<script>
          localStorage.setItem('access_token', '$accessToken');
          localStorage.setItem('refresh_token', '$refreshToken');
          window.location.href = decodeURIComponent('$returnUrl');
        </script>
    ";
} else {
    echo "
        <script>
            window.opener.postMessage({ error: 'Failed to get access token or refresh token' }, '*');
            window.location.href = '$returnUrl';
        </script>
    ";
}
    curl_close($ch);
}
function getAccessTokenBilling($tid, $cId, $rUri, $cSec, $code, $returnUrl) {
  $url = 'https://login.microsoftonline.com/'.$tid.'/oauth2/v2.0/token';
  $headers = [
        'Content-Type: application/x-www-form-urlencoded',
        'Cache-Control: no-cache',
        'Pragma: no-cache'
    ];
  $body = http_build_query([
    'client_id' => $cId,
    'scope' => 'BackupRestore-Control.ReadWrite.All',
    'redirect_uri' => $rUri,
    'client_secret' => $cSec,
    'code' => $code,
    'grant_type' => 'authorization_code'
  ]);
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
curl_setopt($ch, CURLOPT_FRESH_CONNECT, true);
curl_setopt($ch, CURLOPT_FORBID_REUSE, true);
$response = curl_exec($ch);
$responseData = json_decode($response, true);
echo "<script>
    console.log('OAuth2 Token Exchange');
    console.log('Request URL:', '" . $url . "');
    console.log('Request Headers:', " . json_encode($headers) . ");
    console.log('Request Body (string):', `" . addslashes($body) . "`);
    console.log('Raw API Response:', " . json_encode($responseData) . ");
    </script>";
if (isset($responseData['access_token'])) {
$accessToken = $responseData['access_token'];

echo "<script>
    localStorage.setItem('access_token_billing', '$accessToken');
    window.location.href = decodeURIComponent('$returnUrl');
  </script>
";
} else {
echo "
  <script>
      window.opener.postMessage({ error: 'Failed to get access token or refresh token' }, '*');
      window.location.href = '$returnUrl';
  </script>
";
}
curl_close($ch);
}
function getAccessTokenAdminConsent($cId, $rUri, $cSec, $code) {
        $url = 'https://login.microsoftonline.com/common/oauth2/token';
    $headers = [
        'Content-Type: application/x-www-form-urlencoded',
        'Cache-Control: no-cache',
        'Pragma: no-cache'
    ];
    $body = http_build_query([
        'client_id' => $cId,
        'redirect_uri' => $rUri,
        'client_secret' => $cSec,
        'code' => $code,
        'grant_type' => 'authorization_code',
        'resource' => 'https://graph.microsoft.com/'
    ]);
    $ch = curl_init($url);
    curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
    curl_setopt($ch, CURLOPT_FRESH_CONNECT, true);
    curl_setopt($ch, CURLOPT_FORBID_REUSE, true);
    $response = curl_exec($ch);
    $responseData = json_decode($response, true);
    echo "<script>
    console.log('OAuth2 Token Exchange');
    console.log('Request URL:', '" . $url . "');
    console.log('Request Headers:', " . json_encode($headers) . ");
    console.log('Request Body (string):', `" . addslashes($body) . "`);
    console.log('Raw API Response:', " . json_encode($responseData) . ");
    </script>";
    if (isset($responseData['access_token']) && isset($responseData['refresh_token'])) {
    $accessToken = $responseData['access_token'];
    $refreshToken = $responseData['refresh_token'];

    echo "
        <script>
            window.opener.postMessage({ 
                access_token: '$accessToken',
                refresh_token: '$refreshToken'
            }, '*');
            window.close();
        </script>
    ";
} else {
    echo "
        <script>
            window.opener.postMessage({ error: 'Failed to get access token or refresh token' }, '*');
            window.close();
        </script>
    ";
}
    curl_close($ch);
}
function uploadAgent(){
//if (isset($_FILES['updateFileName'])) {
                        $path = "/parablu/updates/";
                        if (!is_dir($path)) {
                    $result = array(
                                'result' => 'fail',
                                'msg' => 'No Directory Found'
                    );
                    die(json_encode($result));
                }
                    $file_name = $_FILES['file']['name'];
                    $file_tmp = $_FILES['file']['tmp_name'];
                    $file_type = $_FILES['file']['type'];
                    $file_size = $_FILES['file']['size'];
                    $file_ext = strtolower(end(explode('.', $_FILES['file']['name'])));
                    $file = $path . $file_name;
                    //$this->log("file :  ".$file,"info");
                    $errors = [];
                        if ($errors) {
                                //$this->log("ERRORS WHILE UPLOADING".json_encode($errors),"info");
                                $result = array(
                                    'result' => 'fail',
                                    'msg'    => 'Failed to upload agent'
                                );
                                die(json_encode($result));
                        }
                            if (empty($errors)) {
                                //$this->log("success ","info");
                                move_uploaded_file($file_tmp, $file);
                                chmod($file, 0777);
                                                $response = array(
                                        'result' => 'success',
                                        'msg'    => 'Agent uploaded succesfully'
                                    );
                                    echo json_encode($response);
                                    exit;
                                        }else{
                                                $response = array(
                                'result' => 'fail',
                                'msg'    => 'Failed to upload agent'
                            );
                            echo json_encode($response);
                            exit;
                                        }
        //}
}
function uploadInfectedFile(){
//if (isset($_FILES['updateFileName'])) {
                        $path = "/parablu/RWSampleFiles/";
                        if (!is_dir($path)) {
                    $result = array(
                                'result' => 'fail',
                                'msg' => 'No Directory Found'
                    );
                    die(json_encode($result));
                }
                    $file_name = $_FILES['file']['name'];
                    $file_tmp = $_FILES['file']['tmp_name'];
                    $file_type = $_FILES['file']['type'];
                    $file_size = $_FILES['file']['size'];
                    $file_ext = strtolower(end(explode('.', $_FILES['file']['name'])));
                    $file = $path . $file_name;
                    //$this->log("file :  ".$file,"info");
                    $errors = [];
                        if ($errors) {
                                //$this->log("ERRORS WHILE UPLOADING".json_encode($errors),"info");
                                $result = array(
                                    'result' => 'fail',
                                    'msg'    => 'Failed to upload file'
                                );
                                die(json_encode($result));
                        }
                            if (empty($errors)) {
                                //$this->log("success ","info");
                                move_uploaded_file($file_tmp, $file);
                                chmod($file, 0777);
                                                $response = array(
                                        'result' => 'success',
                                        'msg'    => 'File uploaded succesfully'
                                    );
                                    echo json_encode($response);
                                    exit;
                                        }else{
                                                $response = array(
                                'result' => 'fail',
                                'msg'    => 'Failed to upload file'
                            );
                            echo json_encode($response);
                            exit;
                                        }
        //}
}
function uploadLicenseKey(){
//if (isset($_FILES['updateFileName'])) {
                        $path = "/parablu/LicenseKey/encryptedFiles/";
                        if (!is_dir($path)) {
                    $result = array(
                                'result' => 'fail',
                                'msg' => 'No Directory Found'
                    );
                    die(json_encode($result));
                }
                    $file_name = $_FILES['file']['name'];
                    $file_tmp = $_FILES['file']['tmp_name'];
                    $file_type = $_FILES['file']['type'];
                    $file_size = $_FILES['file']['size'];
                    $file_ext = strtolower(end(explode('.', $_FILES['file']['name'])));
                    $file = $path . $file_name;
                    //$this->log("file :  ".$file,"info");
                    $errors = [];
                        if ($errors) {
                                //$this->log("ERRORS WHILE UPLOADING".json_encode($errors),"info");
                                $result = array(
                                    'result' => 'fail',
                                    'msg'    => 'Failed to upload License key'
                                );
                                die(json_encode($result));
                        }
                            if (empty($errors)) {
                                //$this->log("success ","info");
                                move_uploaded_file($file_tmp, $file);
                                chmod($file, 0777);
                                                $response = array(
                                        'result' => 'success',
                                        'msg'    => 'License key uploaded succesfully'
                                    );
                                    echo json_encode($response);
                                    exit;
                                        }else{
                                                $response = array(
                                'result' => 'fail',
                                'msg'    => 'Failed to upload License key'
                            );
                            echo json_encode($response);
                            exit;
                                        }
        //}
}
function downloadReport($reportName, $type) {
    // Mapping of report names to their respective file base names
    $reportMapping = [ 
        'dps' => [
            'excel' => AGENT_NOT_HEARD_PATH . 'DataProtectionScorecard.xlsx',
            'pdf' => AGENT_NOT_HEARD_PATH . 'DataProtectionScorecard.pdf',
        ],
        'overview' => [
            'excel' => OVERVIEW_REPORT_PATH . 'Backup_OverviewStatus.xlsx',
            'pdf' => AGENT_NOT_HEARD_PATH . 'Backup_OverviewStatus.pdf',
        ],
        'backupHistory' => [
            'excel' => OVERVIEW_REPORT_PATH . 'BackupHistory.xlsx',
            'pdf' => AGENT_NOT_HEARD_PATH . 'BackupHistory.pdf',
        ],
        'assetsNotProtected' => [
            'excel' => AGENT_NOT_HEARD_PATH . 'AssetsNotProtected.xlsx',
            'pdf' => AGENT_NOT_HEARD_PATH . 'AssetsNotProtected.pdf',
        ],
        'usersWithoutAssetsNotProtected' => [
            'excel' => AGENT_NOT_HEARD_PATH . 'UsersWithoutAnyAssetsProtected.xlsx',
            'pdf' => AGENT_NOT_HEARD_PATH . 'UsersWithoutAnyAssetsProtected.pdf',
        ],
        'restoreHistory' => [
            'excel' => OVERVIEW_REPORT_PATH . 'RestoreHistory.xlsx',
            'pdf' => AGENT_NOT_HEARD_PATH . 'RestoreHistory.pdf',
        ],
        'deviceHeartbeat' => [
            'excel' => AGENT_NOT_HEARD_PATH . 'Device_Heartbeat_Report.xlsx',
            'pdf' => AGENT_NOT_HEARD_PATH . 'Device_Heartbeat_Report.pdf',
        ],
        'assignedAssets' => [
            'excel' => AGENT_NOT_HEARD_PATH . 'Assigned_Assets.xlsx',
            'pdf' => AGENT_NOT_HEARD_PATH . 'Assigned_Assets.pdf',
        ],
    ];
    // Validate the report name and type
    if (!isset($reportMapping[$reportName]) || !isset($reportMapping[$reportName][$type])) {
        header('Location: ' . Url::basePath('users/' . $_GET['from'] . '?result=400'));
        return;
    }
    // Get the file path
    $filePath = $reportMapping[$reportName][$type];
    // Serve the file if it exists, else redirect with a 404 error
    if (file_exists($filePath)) {
      $fileName = basename($filePath);
      if($reportName == 'deviceHeartbeat' && $type == 'excel'){
        $fileName = 'Asset_Heartbeat_Report.xlsx';
      }
      if($reportName == 'deviceHeartbeat' && $type == 'pdf'){
          $fileName = 'Asset_Heartbeat_Report.pdf';
      }
      header('Content-Type: application/csv');
      header('Content-Disposition: attachment; filename=' . $fileName);
      header('Pragma: no-cache');
      ob_clean();
      readfile($filePath);
    } else {
      header('Location: ' . Url::basePath('users/' . $_GET['from'] . '?result=404'));
    }
}
function downloadAgent($type) {
  if ($type == 'windows') {
    $filePath = '/var/lib/parablusys/clients/Parablu_EPA.exe';
    if (file_exists($filePath)) {
      // Set headers to force download
      header('Content-Type: application/octet-stream');
      header('Content-Disposition: attachment; filename="Parablu.exe"'); // Name for the downloaded file
      header('Content-Length: '.filesize($filePath)); // Optional: Send file size
      header('Pragma: no-cache');
      header('Expires: 0');
      // Clear output buffer and read the file
      ob_clean();
      flush(); // Flush system output buffer
      readfile($filePath); // Serve the file
      exit;
    }
  }
  if ($type == 'mac') {
    $filePath = '/var/lib/parablusys/clients/Parablu_EPA.dmg';
    if (file_exists($filePath)) {
      // Set headers to force download
      header('Content-Type: application/octet-stream');
      header('Content-Disposition: attachment; filename="mac_agent.dmg"'); // Name for the downloaded file
      header('Content-Length: '.filesize($filePath)); // Optional: Send file size
      header('Pragma: no-cache');
      header('Expires: 0');
      // Clear output buffer and read the file
      ob_clean();
      flush(); // Flush system output buffer
      readfile($filePath); // Serve the file
      exit;
    }
  }
  if ($type == 'windowsServer') {
    $filePath = '/var/lib/parablusys/clients/Parablu_SA.exe';
    if (file_exists($filePath)) {
      // Set headers to force download
      header('Content-Type: application/octet-stream');
      header('Content-Disposition: attachment; filename="Parablu_SA.exe"'); // Name for the downloaded file
      header('Content-Length: '.filesize($filePath)); // Optional: Send file size
      header('Pragma: no-cache');
      header('Expires: 0');
      // Clear output buffer and read the file
      ob_clean();
      flush(); // Flush system output buffer
      readfile($filePath); // Serve the file
      exit;
    }
  }
  if ($type == 'linuxDeb') {
    $filePath = '/var/lib/parablusys/clients/Parablu_EPA.deb';
    if (file_exists($filePath)) {
      // Set headers to force download
      header('Content-Type: application/octet-stream');
      header('Content-Disposition: attachment; filename="Parablu_EPA.deb"'); // Name for the downloaded file
      header('Content-Length: '.filesize($filePath)); // Optional: Send file size
      header('Pragma: no-cache');
      header('Expires: 0');
      // Clear output buffer and read the file
      ob_clean();
      flush(); // Flush system output buffer
      readfile($filePath); // Serve the file
      exit;
    }
  }
  if ($type == 'linuxRpm') {
    $filePath = '/var/lib/parablusys/clients/Parablu_EPA.rpm';
    if (file_exists($filePath)) {
      // Set headers to force download
      header('Content-Type: application/octet-stream');
      header('Content-Disposition: attachment; filename="Parablu_EPA.rpm"'); // Name for the downloaded file
      header('Content-Length: '.filesize($filePath)); // Optional: Send file size
      header('Pragma: no-cache');
      header('Expires: 0');
      // Clear output buffer and read the file
      ob_clean();
      flush(); // Flush system output buffer
      readfile($filePath); // Serve the file
      exit;
    }
  }
}
function downloadUsersToExcel() {
  $filePath = AGENT_NOT_HEARD_PATH.'Users.xlsx';
  if (file_exists($filePath)) {
    header('Content-Type: application/csv');
    header('Content-Disposition: attachment; filename=Users.xlsx');
    header('Pragma: no-cache');
    ob_clean();
    readfile($filePath);
  } else {
    header('Location: '.Url:: basePath('users/'.$_GET['from'].'?result=404'));
  }
}
function downloadSoftDeletedUsersToExcel() {
  $filePath = AGENT_NOT_HEARD_PATH.'SoftBlockedUsers.xlsx';
  if (file_exists($filePath)) {
    header('Content-Type: application/csv');
    header('Content-Disposition: attachment; filename=SoftBlockedUsers.xlsx');
    header('Pragma: no-cache');
    ob_clean();
    readfile($filePath);
  } else {
    header('Location: '.Url:: basePath('users/'.$_GET['from'].'?result=404'));
  }
}
//dump after bulk operation
function downloadFailedUsersDump() {
  $filePath = AGENT_NOT_HEARD_PATH.'Users_Block_Fail.xlsx';
  if (file_exists($filePath)) {
    header('Content-Type: application/csv');
    header('Content-Disposition: attachment; filename=Users_Fail.xlsx');
    header('Pragma: no-cache');
    ob_clean();
    readfile($filePath);
  } else {
    header('Location: '.Url:: basePath('report/'.$_GET['from'].'?result=404'));
  }
}
//dump after bulk odb target excel
function downloadOdbExcel() {
  $filePath = AGENT_NOT_HEARD_PATH.'OdbMappingFailedUsers.xlsx';
  if (file_exists($filePath)) {
    header('Content-Type: application/csv');
    header('Content-Disposition: attachment; filename=OdbMappingFailedUsers.xlsx');
    header('Pragma: no-cache');
    ob_clean();
    readfile($filePath);
  } else {
    header('Location: '.Url:: basePath('report/'.$_GET['from'].'?result=404'));
  }
}
//download sample for user bulk create operation
function downloadBulkCreateUsersSample() {
  $filePath = OVERVIEW_REPORT_PATH.'bulkCreateUsers.xlsx';
  if (file_exists($filePath)) {
          //header('Content-Type: application/csv');
          header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
    header('Content-Disposition: attachment; filename=bulkCreateUsers.xlsx');
    header('Pragma: no-cache');
    ob_clean();
    readfile($filePath);
  } else {
    header('Location: '.Url:: basePath('report/'.$_GET['from'].'?result=404'));
  }
}
//download sample for user bulk blocl/unblock/delete operation
function downloadBlockUnblockDeleteUsersSample() {
  $filePath = OVERVIEW_REPORT_PATH.'bulkBlockUnblockDeleteUsers.xlsx';
  if (file_exists($filePath)) {
    header('Content-Type: application/csv');
    header('Content-Disposition: attachment; filename=bulkBlockUnblockDeleteUsers.xlsx');
    header('Pragma: no-cache');
    ob_clean();
    readfile($filePath);
  } else {
    header('Location: '.Url:: basePath('report/'.$_GET['from'].'?result=404'));
  }
}
//download sample for user bulk odb login id excel operation
function downloadOdbExcelSample() {
  $filePath = OVERVIEW_REPORT_PATH.'bulkBackupTargetMapping.xlsx';
  if (file_exists($filePath)) {
    header('Content-Type: application/csv');
    header('Content-Disposition: attachment; filename=bulkBackupTargetMapping.xlsx');
    header('Pragma: no-cache');
    ob_clean();
    readfile($filePath);
  } else {
    header('Location: '.Url:: basePath('report/'.$_GET['from'].'?result=404'));
  }
}
function downloadSitesToExcel() {
  $filePath = AGENT_NOT_HEARD_PATH.'Sites.xlsx';
  if (file_exists($filePath)) {
    header('Content-Type: application/csv');
    header('Content-Disposition: attachment; filename=Sites.xlsx');
    header('Pragma: no-cache');
    ob_clean();
    readfile($filePath);
  } else {
    header('Location: '.Url:: basePath('users/'.$_GET['from'].'?result=404'));
  }
}
function downloadAssetsToExcel($productType) {
  if ($productType == 'Sharepoint') {
    $filePath = AGENT_NOT_HEARD_PATH.'Users.xlsx';
    if (file_exists($filePath)) {
      header('Content-Type: application/csv');
      header('Content-Disposition: attachment; filename=Sites.xlsx');
      header('Pragma: no-cache');
      ob_clean();
      readfile($filePath);
      exit;
    } else {
      header('Location: '.Url:: basePath('devices/'.$_GET['from'].'?result=404'));
    }
  } elseif($productType == 'server'){
    $filePath = AGENT_NOT_HEARD_PATH.'Devices.xlsx';
    if (file_exists($filePath)) {
      header('Content-Type: application/csv');
      header('Content-Disposition: attachment; filename=Servers.xlsx');
      header('Pragma: no-cache');
      ob_clean();
      readfile($filePath);
      exit;
    }
  }else {
    $filePath = AGENT_NOT_HEARD_PATH.'Devices.xlsx';
    if (file_exists($filePath)) {
      header('Content-Type: application/csv');
      header('Content-Disposition: attachment; filename=Assets.xlsx');
      header('Pragma: no-cache');
      ob_clean();
      readfile($filePath);
      exit;
    }
  }
}
function downloadServersToExcel() {
  $filePath = AGENT_NOT_HEARD_PATH.'Devices.xlsx';
  if (file_exists($filePath)) {
    header('Content-Type: application/csv');
    header('Content-Disposition: attachment; filename=Servers.xlsx');
    header('Pragma: no-cache');
    ob_clean();
    readfile($filePath);
  } else {
    header('Location: '.Url:: basePath('devices/'.$_GET['from'].'?result=404'));
  }
}
//dump after assets bulk operation
function downloadFailedAssetsDump() {
  $filePath = AGENT_NOT_HEARD_PATH.'Asset_Block_Fail.xlsx';
  if (file_exists($filePath)) {
    header('Content-Type: application/csv');
    header('Content-Disposition: attachment; filename=Asset_Fail.xlsx');
    header('Pragma: no-cache');
    ob_clean();
    readfile($filePath);
  } else {
    header('Location: '.Url:: basePath('report/'.$_GET['from'].'?result=404'));
  }
}
//for devices bulk operation
function downloadBlockUnblockAssetsSample() {
  $filePath = OVERVIEW_REPORT_PATH.'bulkBlockUnblockDeleteAssets.xlsx';
  if (file_exists($filePath)) {
    header('Content-Type: application/csv');
    header('Content-Disposition: attachment; filename=bulkBlockUnblockDeleteAssets.xlsx');
    header('Pragma: no-cache');
    ob_clean();
    readfile($filePath);
  } else {
    header('Location: '.Url:: basePath('report/'.$_GET['from'].'?result=404'));
  }
}
function downloadBlockUnblockSitesSample() {
  $filePath = OVERVIEW_REPORT_PATH.'bulkBlockUnblockDeleteSites.xlsx';
  if (file_exists($filePath)) {
    header('Content-Type: application/csv');
    header('Content-Disposition: attachment; filename=bulkBlockUnblockDeleteSites.xlsx');
    header('Pragma: no-cache');
    ob_clean();
    readfile($filePath);
  } else {
    header('Location: '.Url:: basePath('report/'.$_GET['from'].'?result=404'));
  }
}
function downloadSharepointPolicyPdf($policyName) {
  $filePath = AGENT_NOT_HEARD_PATH.$policyName."_Policy.pdf";
  if (file_exists($filePath)) {
    header('Content-Type: application/csv');
    header('Content-Disposition: attachment; filename="'.$policyName. '.pdf"');
    header('Pragma: no-cache');
    ob_clean();
    readfile($filePath);
  } else {
    header('Location: '.Url:: basePath('report/'.$_GET['from'].'?result=404'));
  }
}
function downloadOnedrivePolicyFilePdf($policyName) {
  $filePath = AGENT_NOT_HEARD_PATH.$policyName."_Policy.pdf";
  if (file_exists($filePath)) {
    header('Content-Type: application/csv');
    header('Content-Disposition: attachment; filename="'.$policyName. '.pdf"');
    header('Pragma: no-cache');
    ob_clean();
    readfile($filePath);
  } else {
    header('Location: '.Url:: basePath('report/'.$_GET['from'].'?result=404'));
  }
}
function downloadExchangePolicyFilePdf($policyName) {
  $filePath = AGENT_NOT_HEARD_PATH.$policyName."_Policy.pdf";
  if (file_exists($filePath)) {
    header('Content-Type: application/csv');
    header('Content-Disposition: attachment; filename="'.$policyName. '.pdf"');
    header('Pragma: no-cache');
    ob_clean();
    readfile($filePath);
  } else {
    header('Location: '.Url:: basePath('report/'.$_GET['from'].'?result=404'));
  }
}
function downloadPolicyFilePdf($policyName) {
  $filePath = AGENT_NOT_HEARD_PATH.$policyName."_Policy.pdf";
  if (file_exists($filePath)) {
    header('Content-Type: application/csv');
    header('Content-Disposition: attachment; filename="'.$policyName. '.pdf"');
    header('Pragma: no-cache');
    ob_clean();
    readfile($filePath);
  } else {
    header('Location: '.Url:: basePath('report/'.$_GET['from'].'?result=404'));
  }
}
function downloadPolicyFailDump() {
  $filePath = AGENT_NOT_HEARD_PATH.'Users_Policy_Mapping_Fail.xlsx';
  if (file_exists($filePath)) {
    header('Content-Type: application/csv');
    header('Content-Disposition: attachment; filename=Users_Policy_Mapping_Fail.xlsx');
    header('Pragma: no-cache');
    ob_clean();
    readfile($filePath);
  } else {
    header('Location: '.Url:: basePath('report/'.$_GET['from'].'?result=404'));
  }
}
function downloadSimpleBulkPolicyMappingSample() {
  $filePath = OVERVIEW_REPORT_PATH.'bulkBlockUnblockDeleteUsers.xlsx';
  if (file_exists($filePath)) {
    header('Content-Type: application/csv');
    header('Content-Disposition: attachment; filename='.'bulkPolicyMapping.xlsx');
    header('Pragma: no-cache');
    ob_clean();
    readfile($filePath);
  } else {
    header('Location: '.Url:: basePath('report/'.$_GET['from'].'?result=404'));
  }
}
function downloadAdvancedBulkPolicyMappingSample() {
  $filePath = OVERVIEW_REPORT_PATH.'bulkBlockUnblockDeleteUsersAdvanced.xlsx';
  if (file_exists($filePath)) {
    header('Content-Type: application/csv');
    header('Content-Disposition: attachment; filename='.'bulkPolicyMapping.xlsx');
    header('Pragma: no-cache');
    ob_clean();
    readfile($filePath);
  } else {
    header('Location: '.Url:: basePath('report/'.$_GET['from'].'?result=404'));
  }
}
function downloadExportUnusualActivityHistoryToExcel($userName) {
  $filePath = OVERVIEW_REPORT_PATH.'UnusualActivity_Audit_Overview_'.$userName.'.xls';
  if (file_exists($filePath)) {
    header('Content-Type: application/csv');
    header('Content-Disposition: attachment; filename=UnusualActivity_Audit_Overview_'.$userName.'.xls');
    header('Pragma: no-cache');
    ob_clean();
    readfile($filePath);
  } else {
    header('Location: '.Url:: basePath('/report/'.$_GET['from'].'?result=404'));
  }
}
function downloadExportActivityHistoryToExcel($userName) {
  $filePath = OVERVIEW_REPORT_PATH.'Audit_Overview_'.$userName.'.xls';
  if (file_exists($filePath)) {
    header('Content-Type: application/csv');
    header('Content-Disposition: attachment; filename=Audit_Overview_'.$userName.'.xls');
    header('Pragma: no-cache');
    ob_clean();
    readfile($filePath);
  } else {
    header('Location: '.Url:: basePath('/report/'.$_GET['from'].'?result=404'));
  }
}
function downloadUserMigrationExcel() {
  $filePath = OVERVIEW_REPORT_PATH.'UserMigrationStatus.xlsx';
  if (file_exists($filePath)) {
    header('Content-Type: application/csv');
    header('Content-Disposition: attachment; filename=UserMigrationStatus.xlsx');
    header('Pragma: no-cache');
    ob_clean();
    readfile($filePath);
  } else {
    header('Location: '.Url:: basePath('report/'.$_GET['from'].'?result=404'));
  }
}
function downloadLog($id, $name) {
  if (!empty($id) && !empty($name)) {
    $path = '/parablu/support/bslogs/'.$id.'/'.$name;
    if (!is_file($path)) {
                echo "File Not Found.";
    }
    HEADER("Cache-Control: private");
    HEADER("Pragma: public");
    HEADER("Expires: ".GMDATE("D, d M Y H:i:s", MKTIME(DATE("H") + 2, DATE("i"), DATE("s"), DATE("m"), DATE("d"), DATE("Y")))." GMT");
    HEADER("Last-Modified: ".GMDATE("D, d M Y H:i:s")." GMT");
    HEADER("Content-Type: application/octet-stream");
    HEADER("Content-Length: ".(string)(FILESIZE($path)));
    HEADER("Content-Disposition: attachment; filename=".$name);
    HEADER("Content-Transfer-Encoding: binary");
    if ($file = FOPEN($path, 'rb')) {
      while (!FEOF($file) && (CONNECTION_STATUS() == 0)) {
        PRINT(FREAD($file, 1024 * 8));
        FLUSH();
      }
      FCLOSE($file);
    }
    return ((CONNECTION_STATUS() == 0) && !CONNECTION_ABORTED());
  } else {
            echo "File Not Found.";
  }
}
function downloadUserMigrationSample() {
  $filePath = OVERVIEW_REPORT_PATH.'bulkBlockUnblockDeleteUsers.xlsx';
  if (file_exists($filePath)) {
    header('Content-Type: application/csv');
    header('Content-Disposition: attachment; filename=userMigrationSample.xlsx');
    header('Pragma: no-cache');
    ob_clean();
    readfile($filePath);
  } else {
    header('Location: '.Url:: basePath('report/'.$_GET['from'].'?result=404'));
  }
}
function uploadLoginLogo(){
  $path = "/var/www/portal/assets/brand/";
  if (!is_dir($path)) {
    $result = array(
      'result' => 'fail',
      'msg' => 'No Directory Found'
    );
    die(json_encode($result));
  }
  $file_name = $_FILES['file']['name'];
  $file_tmp = $_FILES['file']['tmp_name'];
  $file_type = $_FILES['file']['type'];
  $file_size = $_FILES['file']['size'];
  $file_ext = strtolower(end(explode('.', $_FILES['file']['name'])));
  $file = $path . 'login_logo.png';
  $errors = [];
  if ($errors) {
    $result = array(
      'result' => 'fail',
      'msg'    => 'Failed to upload Login Page Logo'
    );
    die(json_encode($result));
  }
  if (empty($errors)) {
    move_uploaded_file($file_tmp, $file);
    chmod($file, 0777);
    $response = array(
      'result' => 'success',
      'msg'    => 'Login Page Logo uploaded succesfully'
    );
    echo json_encode($response);
    exit;
  }else{
    $response = array(
      'result' => 'fail',
      'msg'    => 'Failed to upload Login Page Logo'
    );
    echo json_encode($response);
    exit;
  }
}
function uploadHeaderLogo(){
  $path = "/var/www/portal/assets/brand/";
  if (!is_dir($path)) {
    $result = array(
      'result' => 'fail',
      'msg' => 'No Directory Found'
    );
    die(json_encode($result));
  }
  $file_name = $_FILES['file']['name'];
  $file_tmp = $_FILES['file']['tmp_name'];
  $file_type = $_FILES['file']['type'];
  $file_size = $_FILES['file']['size'];
  $file_ext = strtolower(end(explode('.', $_FILES['file']['name'])));
  $file = $path . 'header_logo.png';
  $errors = [];
  if ($errors) {
    $result = array(
      'result' => 'fail',
      'msg'    => 'Failed to upload Header Logo'
    );
    die(json_encode($result));
  }
  if (empty($errors)) {
    move_uploaded_file($file_tmp, $file);
    chmod($file, 0777);
    $response = array(
      'result' => 'success',
      'msg'    => 'Header Logo uploaded succesfully'
    );
    echo json_encode($response);
    exit;
  }else{
    $response = array(
      'result' => 'fail',
      'msg'    => 'Failed to upload Header Logo'
    );
    echo json_encode($response);
    exit;
  }
}
function uploadDisclaimer(){
  $path = "/var/www/portal/assets/brand/";
  if (!is_dir($path)) {
    $result = array(
      'result' => 'fail',
      'msg' => 'No Directory Found'
    );
    die(json_encode($result));
  }
  $file_name = $_FILES['file']['name'];
  $file_tmp = $_FILES['file']['tmp_name'];
  $file_type = $_FILES['file']['type'];
  $file_size = $_FILES['file']['size'];
  $file_ext = strtolower(end(explode('.', $_FILES['file']['name'])));
  $file = $path . 'disclaimer.txt';
  $errors = [];
  if ($errors) {
    $result = array(
      'result' => 'fail',
      'msg'    => 'Failed to upload Disclaimer File'
    );
    die(json_encode($result));
  }
  if (empty($errors)) {
    move_uploaded_file($file_tmp, $file);
    chmod($file, 0777);
    $response = array(
      'result' => 'success',
      'msg'    => 'Disclaimer File uploaded succesfully'
    );
    echo json_encode($response);
    exit;
  }else{
    $response = array(
      'result' => 'fail',
      'msg'    => 'Failed to upload Login Page Logo'
    );
    echo json_encode($response);
    exit;
  }
}
function uploadCustomEmail(){
  $path = "/var/www/portal/assets/brand/";
  if (!is_dir($path)) {
    $result = array(
      'result' => 'fail',
      'msg' => 'No Directory Found'
    );
    die(json_encode($result));
  }
  $file_name = $_FILES['file']['name'];
  $file_tmp = $_FILES['file']['tmp_name'];
  $file_type = $_FILES['file']['type'];
  $file_size = $_FILES['file']['size'];
  $file_ext = strtolower(end(explode('.', $_FILES['file']['name'])));
  $file = $path . 'emails.xml';
  $errors = [];
  if ($errors) {
    $result = array(
      'result' => 'fail',
      'msg'    => 'Failed to upload Custom Email Template File'
    );
    die(json_encode($result));
  }
  if (empty($errors)) {
    move_uploaded_file($file_tmp, $file);
    chmod($file, 0777);
    $response = array(
      'result' => 'success',
      'msg'    => 'Custom Email Template File uploaded succesfully'
    );
    echo json_encode($response);
    exit;
  }else{
    $response = array(
      'result' => 'fail',
      'msg'    => 'Failed to upload Custom Email Template File'
    );
    echo json_encode($response);
    exit;
  }
}
function uploadGettingStarted(){
  $path = "/var/www/portal/assets/brand/";
  if (!is_dir($path)) {
    $result = array(
      'result' => 'fail',
      'msg' => 'No Directory Found'
    );
    die(json_encode($result));
  }
  $file_name = $_FILES['file']['name'];
  $file_tmp = $_FILES['file']['tmp_name'];
  $file_type = $_FILES['file']['type'];
  $file_size = $_FILES['file']['size'];
  $file_ext = strtolower(end(explode('.', $_FILES['file']['name'])));
  $file = $path . 'gettingStarted.pdf';
  $errors = [];
  if ($errors) {
    $result = array(
      'result' => 'fail',
      'msg'    => 'Failed to upload User Manual Guide'
    );
    die(json_encode($result));
  }
  if (empty($errors)) {
    move_uploaded_file($file_tmp, $file);
    chmod($file, 0777);
    $response = array(
      'result' => 'success',
      'msg'    => 'User Manual Guide uploaded succesfully'
    );
    echo json_encode($response);
    exit;
  }else{
    $response = array(
      'result' => 'fail',
      'msg'    => 'Failed to upload User Manual Guide'
    );
    echo json_encode($response);
    exit;
  }
}
function downloadFailedFiles($deviceUUID, $batchId){
  $fileNameA = "failedFile.csv";
  $fileNameB = "failedFile.log";
  $path = "/parablu/support/failedFileslogs/";
  $pathA = $path . $deviceUUID . '/' . $batchId . '/' . $fileNameA;
  $pathB = $path . $deviceUUID . '/' . $batchId . '/' . $fileNameB;

  // Check for required params
  if (empty($deviceUUID) || empty($batchId)) {
    http_response_code(400);
    echo json_encode([
      'result' => 'fail',
      'message' => 'Missing deviceUUID or batchId'
    ]);
    exit;
  }

  // Check if neither file exists
  if (!is_file($pathA) && !is_file($pathB)) {
    http_response_code(404);
    echo json_encode([
      'result' => 'fail',
      'message' => 'Log file not present'
    ]);
    exit;
  }

  // Helper to download file
  function outputDownload($fullPath, $fileName) {
    if (ob_get_level()) ob_end_clean();
    header("Cache-Control: private");
    header("Pragma: public");
    header("Expires: " . gmdate("D, d M Y H:i:s", mktime(date("H")+2, date("i"), date("s"), date("m"), date("d"), date("Y"))) . " GMT");
    header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
    header("Content-Type: application/octet-stream");
    header("Content-Length: " . filesize($fullPath));
    header("Content-Disposition: attachment; filename=" . $fileName);
    header("Content-Transfer-Encoding: binary");
    session_write_close(); // Important for large file download
    if ($file = fopen($fullPath, 'rb')) {
      while (!feof($file) && connection_status() == 0) {
        print(fread($file, 1024 * 8));
        flush();
      }
      fclose($file);
    }
    exit;
  }
  // Serve first available file
  if (is_file($pathA)) {
    outputDownload($pathA, $fileNameA);
  } else if (is_file($pathB)) {
    outputDownload($pathB, $fileNameB);
  }
}
if (isset($_GET['function'])) {
  $functionName = $_GET['function'];
  if (in_array($functionName, $allowedFunctions)) {
    $params = $_GET['params'] ?? [];
    if (is_string($params)) {
      $params = explode(',', $params);
    }
    try {
      call_user_func_array($functionName, $params);
    } catch (Exception $e) {
            echo "Error executing function: ".$e -> getMessage();
    }
  } else {
        echo "Function '$functionName' is not allowed.";
  }
} else {
    echo "No function specified.";
}
?>