<?php
class WMInstaller
{
    private $title = 'Werbe-Markt.de Modulverwaltung installieren';
    private $version = '1.0.0';
    private $checksum = '1bfb4c215af8576703a00333f220a853';
    private $minPhpVersion = '7.2.0';

    public function __construct() {
        foreach (['../', '../../'] as $dir) {
            if (!file_exists('includes/application_top.php') && file_exists($dir . 'includes/application_top.php')) {
                rename('./wm_install.php', $dir . 'wm_install.php');
                header('Location:' . $dir . 'wm_install.php');
                exit;
            }
        }
        include 'includes/application_top.php';
        if (isset($_POST['action'])) {
            $action = $_POST['action'];
            $this->$action();
        }
        if (!isset($GLOBALS['PHP_SELF'])) {
            $GLOBALS['PHP_SELF'] = 'wm_install.php';
        }
        $isLoggedInAsAdmin = isset($_SESSION['customers_status']['customers_status_id']) && (defined('DEFAULT_CUSTOMERS_STATUS_ID_ADMIN') ? ((int)DEFAULT_CUSTOMERS_STATUS_ID_ADMIN) : 0) === (int)$_SESSION['customers_status']['customers_status_id'];
        $this->printPage($isLoggedInAsAdmin);
    }

    private function respond($msg = ['success' => true]) {
        echo json_encode($msg);
        exit;
    }

    private function isZipSupported() {
        if (class_exists('ZipArchive')) {
            $this->respond();
        } else {
            $this->respond(['success' => false, 'continue' => false, 'msg' => '<a href="https://www.php.net/manual/de/class.ziparchive.php" rel="noopener noreferrer">PHP ZipArchive</a> erforderlich! Bitte an Serveradmin oder Webhoster wenden!']);
        }
    }

    private function checkDirectories() {
        if ($this->checkDirectory('./cache') && $this->checkDirectory('./includes/external') && (!is_dir('./includes/external/WMInstaller') || $this->checkDirectory('./includes/external/WMInstaller'))) {
            $this->respond();
        } else {
            $this->respond(['success' => false, 'continue' => false, 'msg' => 'Bitte prüfen Sie, dass sich die wm_install.php im Wurzelverzeichnis Ihres Shops befindet und das cache sowie includes/external-Verzeichnis beschreibbar sind (Zugriffsrechte via FTP-Programm setzen)!']);
        }
    }

    private function checkDirectory($dir) {
        if (is_dir($dir) && function_exists('is_writeable') && is_writable($dir)) {
            return true;
        }
        $file = $dir . '/' . uniqid();
        if (@touch($file)) {
            unlink($file);
            return true;
        }
        return false;
    }

    private function getZipFile() {
        $ch = curl_init('https://www.werbe-markt.de/shop_api/modified_v1/');
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query(['action' => 'getFile', 'id' => 211767, 'version' => $this->version]));
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        $res = curl_exec($ch);
        $curlErr = curl_error($ch);
        curl_close($ch);
        if (!empty($curlErr)) {
            $this->respond(['success' => false, 'continue' => false, 'msg' => 'Die Zip-Datei konnte nicht heruntergeladen werden! cURL-Fehler:<br>' . $curlErr]);
        } elseif (!empty($res)) {
            file_put_contents('./cache/WMInstaller.zip', base64_decode($res));
            $this->respond();
        }
        $this->respond(['success' => false, 'continue' => false, 'msg' => 'Die Zip-Datei konnte nicht heruntergeladen werden!']);
    }

    private function checkZipFile() {
        if (md5_file('./cache/WMInstaller.zip') === $this->checksum) {
            $this->respond();
        }
        $this->respond(['success' => false, 'continue' => false, 'msg' => 'Die Zip-Datei scheint beschädigt zu sein!']);
    }

    private function extractZip() {
        $zip = new ZipArchive();
        if ($zip->open('./cache/WMInstaller.zip') === true) {
            $srcDir = './cache/tmp_install';
            if (!file_exists($srcDir)) {
                mkdir($srcDir, 0777);
            }
            $zip->extractTo($srcDir);
            $zip->close();
            if (is_dir($srcDir . '/WMInstaller')) {
                $this->copyDir($srcDir . '/WMInstaller', '.');
            } else {
                $this->respond(['success' => false, 'continue' => false, 'msg' => 'Die Zip-Datei scheint beschädigt zu sein!']);
            }
            $this->respond();
        } else {
            $this->respond(['success' => false, 'continue' => false, 'msg' => 'Die Zip-Datei scheint beschädigt zu sein!']);
        }
    }

    private function setAdminAccess() {
		$this->addTableColumns('admin_access', 'wm_installer', "INT unsigned NOT NULL DEFAULT 0");
		$query="UPDATE `admin_access` SET `wm_installer`=1 WHERE customers_id=" . (int)$_SESSION['customer_id'];
		xtc_db_query($query);
        $this->respond();
    }

    private function deleteZip() {
        $file = './cache/WMInstaller.zip';
        if (!file_exists($file) || unlink($file)) {
            $this->respond();
        } else {
            $this->respond(['success' => false, 'continue' => true, 'msg' => 'Die Datei ' . $file . ' konnte nicht gelöscht werden. Bitte löschen Sie die Datei manuell.']);
        }
    }

    private function deleteTmpDir() {
        $dir = './cache/tmp_install';
        $this->cleanDir($dir);
        if (!file_exists($dir)) {
            $this->respond();
        } else {
            $this->respond(['success' => false, 'continue' => true, 'msg' => 'Das temporäre Verzeichnis ' . $dir . ' konnte nicht gelöscht werden. Bitte löschen Sie es manuell.']);
        }
    }

    private function deleteInstallFile() {
        if ((!isset($_SERVER['HTTP_HOST']) || !in_array($_SERVER['HTTP_HOST'], ['bumbio.de', 'modified.de'])) && unlink(__FILE__)) {
            $this->respond(['success' => true, 'msg' => '<p class="text-left alert alert-success">Die Installation war erfolgreich!</p><a href="'. DIR_ADMIN . 'wm_installer.php?welcome"><button class="btn btn-primary">zur Modulverwaltung</button></a>']);
        } else {
            $this->respond(['success' => false, 'continue' => true, 'msg' => 'Die Datei ./wm_install.php konnte nicht gelöscht werden. Bitte löschen Sie die Datei manuell.']);
        }
    }

    private function addTableColumns(string $table, string $col, string $addQuery): void {
        $addColumn = true;
        $query = "SHOW COLUMNS FROM `" . $table . "` LIKE '" . $col . "'";
        $res = xtc_db_query($query);
        while ($date = xtc_db_fetch_array($res)) {
            $addColumn = false;
        }
        if ($addColumn) {
            $query = "ALTER TABLE `" . $table . "` ADD `" . $col . "` " . $addQuery;
            xtc_db_query($query);
        }
    }

    private function cleanDir($dir) {
        if (strpos($dir, '/cache/tmp_install') !== false && is_dir($dir)) {
            foreach (array_diff(scandir($dir), ['..', '.']) as $file) {
                if (is_dir($dir . '/' . $file)) {
                    $this->cleanDir($dir . '/' . $file);
                } else {
                    unlink($dir . '/' . $file);
                }
            }
            if (count(scandir($dir)) == 2) {
                rmdir($dir);
            }
        }
    }

    private function copyDir($src, $dst) {
        if (!file_exists($dst)) {
            mkdir($dst, 0777, true);
        }
        foreach (array_diff(scandir($src), ['..', '.']) as $file) {
            if (is_dir($src . '/' . $file)) {
                $this->copyDir($src . '/' . $file, $dst . '/' . ($file !== 'admin' ? $file : (defined('DIR_ADMIN') ? rtrim(DIR_ADMIN, '/') : 'admin')));
            } else {
                copy($src . '/' . $file, $dst . '/' . $file);
            }
        }
    }

    public function printPage(bool $isLoggedInAsAdmin) {
        ?><!DOCTYPE html>
<html lang="de">
   <head>
      <meta charset="utf-8" />
      <title><?php echo $this->title; ?></title>
      <link href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
      <style>
         .progress{
         display:none;
         }
         .card-body{
         width:600px;margin:0 auto;
         }
      </style>
   </head>
   <body>
      <div class="card" id="installCard">
         <div class="card-header text-center">
            <?php echo $this->title; ?>
         </div>
         <div class="card-body">
            <?php if (version_compare(PHP_VERSION, $this->minPhpVersion, '<')) { ?>
            <p class="alert alert-danger">Die verwendete PHP-Version <?php echo PHP_VERSION; ?> ist leider <a href="https://www.php.net/supported-versions.php" rel="noopener noreferrer">veraltet</a>. Die Modulverwaltung benötigt mindestens PHP <?php echo $this->minPhpVersion; ?>.</p>
            <?php } elseif ($isLoggedInAsAdmin) { ?>
            <ul class="list-group center-block">
               <?php foreach (['isZipSupported' => 'Prüfe Zip-Funktionalität', 'checkDirectories' => 'Prüfe Dateistruktur', 'getZipFile' => 'Lade Zip-Paket', 'checkZipFile' => 'Prüfe Integrität', 'extractZip' => 'Entpacke Moduldateien', 'setAdminAccess' => 'Setze Adminrechte (Zugriff auf Modulverwaltung)', 'deleteZip' => 'Lösche Zip-Datei', 'deleteTmpDir' => 'Lösche temporäres Verzeichnis', 'deleteInstallFile' => 'Lösche Installations-Datei'] as $action => $actionName) { ?>
               <li class="list-group-item d-flex justify-content-between align-items-center" data-action="<?php echo $action; ?>">
                  <?php echo $actionName; ?>
                  <span class="badge badge-pill"></span>
               </li>
               <?php
               } ?>
            </ul>
            <?php
            } else { ?>
            <p class="alert alert-danger">Bitte zunächst als Shop-Administrator <a href="login_admin.php" target="_blank">einloggen</a>.</p>
            <?php
            } ?>
         </div>
         <div class="card-body text-right">
            <div class="progress">
               <div class="progress-bar" role="progressbar" id="progressbar">&nbsp;</div>
            </div>
            <?php if ($isLoggedInAsAdmin) { ?>
            <button class="btn btn-primary" id="installButton">Installation starten</button>
            <?php
            } else { ?>
            <button class="btn btn-primary" id="reloadButton">Seite neu laden</button>
            <?php
            } ?>
         </div>
         <div class="card-footer text-muted text-center">
            <small>Version <?php echo $this->version; ?></small>
         </div>
      </div>
      <script src="https://code.jquery.com/jquery-3.5.1.min.js" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script>
      <script>
         $('#installButton').on('click',function(){
         	$(this).remove();
         	$('.progress').show();
         	doInstall($('li[data-action]').first());
         });
         $('#reloadButton').on('click',function(){
         	location.reload();
         });
         function doInstall(li){
         	$('#progressbar').css({width:($('#installCard .badge-success,#installCard .badge-danger').length/$('#installCard li').length*100)+'%'});
         	var spinner=$('<div/>').attr('class','spinner-border spinner-border-sm').attr('role','status').appendTo(li);
         	var action=li.data('action');
         	var url='wm_install.php';
         	$.ajax({
         	  type: 'POST',
         	  url: url,
         	  data: {action:action},
         	  complete: function(msg){
         		  var msg=msg.responseJSON;
         			var badge=li.find('.badge');
         			spinner.remove();
         			if (msg.success){
         				badge.addClass('badge-success').text('✔️');
         				if (li.next('li').length===0){
         					$('.progress').replaceWith(msg.msg);
							return;
						}
         			}else{
         				badge.addClass('badge-danger').html('X');
         				$('.progress').before('<p class="text-left alert alert-'+(msg.continue?'warning':'danger')+'">'+msg.msg+'</p>');
         				if (!msg.continue){
         					$('.progress').remove();
         				}
         			}
         			if (msg.success || msg.continue && (li.next('li').length>0)){
         				return doInstall(li.next(li));
         			}
         		},
         	  dataType: (action!=='cache'?'JSON':'HTML')
         	});
         }
      </script>
   </body>
</html>
<?php
    }
}
new WMInstaller();
