<?php
/* ######################################################################

  IML DEPLOYMENT

  CONFIG CHECKER for new setups

  ---------------------------------------------------------------------
  2017-12-01  Axel <axel.hahn@iml.unibe.ch>
  ###################################################################### */



// ----------------------------------------------------------------------
// functions
// ----------------------------------------------------------------------

/**
 * get html code to draw a colored box
 * @param string  $s       message
 * @param string  $sClass  css class; one of ok|info|error
 * @return string
 */
function drawbox($s, $sClass) {
    return '<div class="box ' . $sClass . '">' . $s . '</div>';
}

/**
 * show an alert box with error message
 * @param type $s
 * @return type
 */
function showerror($s) {
    return drawbox($s, 'error');
}

/**
 * show green box with ok message
 * @param type $s
 * @return type
 */
function showok($s) {
    return drawbox($s, 'ok');
}

/**
 * check a directory if it exists and is writtable
 * @global array  $aErrors  found errors
 * @param string  $sDir     directory to check
 * @param string  $sKey     key in config (for output only)
 * @return boolean
 */
function checkdir($sDir, $sKey = false) {
    global $aErrors;

    echo 'check directory [' . $sDir . '] ';
    if (!is_dir($sDir)) {
        echo '<span class="error">does not exist</span><br>';
        $aErrors[] = "* \$aConfig['$sKey'] points to a non existing directory (" . $sDir . ").\n";
        return false;
    } else {
        if (!is_writable($sDir)) {
            echo '<span class="error">not writable</span><br>';
            $aErrors[] = "* \$aConfig['$sKey'] = " . $sDir . " is NOT writable.\n";
            return false;
        } else {
            echo '<span class="ok">OK</span> exists and is writable<br>';
            return true;
        }
    }
    return false;
}

/**
 * check if a php module was found
 * @global array  $aErrors  found errors
 * @param  array  $aRequiredMods  array with needed php modules; default: empty = list all current php modules
 * @return boolean
 */
function checkModule($aRequiredMods=array()){
    global $aErrors;
    $sReturn='';
    
    $aAllMods=get_loaded_extensions(false);
    asort($aAllMods);
    if(!count($aRequiredMods)){
        echo '<strong>List of all installes php modules</strong><br>';
        foreach($aAllMods as $sMod){
            echo $sMod.'<br>';
        }
    } else {
        foreach($aRequiredMods as $sMod){
            echo $sMod.' - ';
            if(!array_search($sMod, $aAllMods)===false){
                echo  '<span class="ok">OK</span> installed';
            } else {
                echo '<span class="error">does not exist</span>';
                $aErrors[] = "* php module $sMod was not found.\n";
            }
            echo '<br>';
        }
    }
    return true;   
}

/**
 * check if a command can be executed
 * @global array  $aErrors  found errors
 * @param  array  $aCommands  array with key=command + value=description
 * @return boolean
 */
function checkCommands($aCommands){
    global $aErrors;
    foreach ($aCommands as $sCommand=>$sDescription){
            echo 'command ['.$sCommand.'] ('.$sDescription.') - ';
            system("$sCommand", $iReturn);
            
            if($iReturn===0){
                echo  '<span class="ok">OK</span> ';
            } else {
                echo '<span class="error">does not exist</span>';
                $aErrors[] = "* command $sCommand was not found or failed.\n";
            }
            echo '<br>';
    }
    return true;
}

// ----------------------------------------------------------------------
// 
// main
// 
// ----------------------------------------------------------------------

echo '
<style>
    body{font-family: arial; background: #f8f8f8; color:#345;}
    .box{border: 2px solid rgba(0,0,0,0.2); padding: 1em; margin-bottom: 1em;}
    .ok{color:#383; background:#cfd;}
    .error{color:#833; background:#fdd;}
</style>
<h1>Config Checker</h1>
';

$aErrors = array();
include("../config/inc_projects_config.php");
if (!isset($aConfig) || !is_array($aConfig)) {
    // echo showerror("\$aConfig does not exist. The config was not included before including " . __FILE__ . " in the request/ script.");
    $aErrors[] = "* \$aConfig does not exist. The config was not included before including " . __FILE__ . " in the request/ script.";
} else {
    
    // ----------------------------------------------------------------------
    echo '<h2>Check keys with directories</h2>';
    foreach (array(
        'appRootDir',
        'configDir',
        'workDir',
        'dataDir',
        'buildDir',
        'buildDefaultsDir',
        'packageDir',
        'archiveDir',
    ) as $sKey) {
        checkdir($aConfig[$sKey], $sKey);
    }
    
    echo '<h2>Check subdirs of key dataDir</h2>';
    foreach (array(
            $aConfig['dataDir'] . '/database',
            $aConfig['dataDir'] . '/projects',
            $aConfig['dataDir'] . '/sshkeys',
        ) as $sDir2Check) {
        checkdir($sDir2Check, 'dataDir + [subdir]');
    }
    
    // ----------------------------------------------------------------------
    echo '<h2>Check keys</h2>';
    // check required keys in the config
    foreach (array(
    'auth',
     'hooks',
     'installPackages',
     'lang',
     'phases',
     'projects',
    ) as $sKey) {
        echo "Key [$sKey] ";
        if (!array_key_exists($sKey, $aConfig)) {
            echo '<span class="error">failed</span> missing key [$sKey] in config<br>';
            $aErrors[] = "* missing key [$sKey] in config\n";
        } else {
            echo '<span class="ok">OK</span> exists<br>';
        }
    }
}

echo '<h2>Check required PHP modules</h2>';
echo 'PHP version: '.PHP_VERSION.'<br>'
        . '<br>';
checkModule(array(
    'PDO','curl', 'json', 'ldap', 'pdo_sqlite'
));

echo '<h2>Check executable commands</h2>'
    . '<p>remark: if the apache user has no login shell then all commands will fail.</p>';
echo '<h3>basic tools</h3>';
checkCommands(array(
    'which bash'=>'shell interpreter to execute hook scripts', 
    'which cat'=>'show content of files', 
    'which cp'=>'copy files', 
    'which ln'=>'create softlinks for version handling', 
    'which ls'=>'list files', 
    'which mkdir'=>'create working directories', 
    'which mv'=>'move files', 
    'which ps'=>'process list',
    'which rm'=>'remove files and directories', 
));
echo '<h3>more tools</h3>';
checkCommands(array(
    'which ssh'=>'connect with ssh for remote execution',
    'which rsync'=>'sync packages to puppet master',
    'which git'=>'connect to git repositories',
));
echo '<h3>tools for IML projects</h3>';
checkCommands(array(
    'which uglifyjs'=>'compress js',
    'which yui-compressor'=>'compress js, css',
    'which nodejs'=>'Nodejs - Javascript v8',
    'which yarn'=>'nodejs package manager',
));



echo '<h2>Result</h2>';

if (count($aErrors)) {
    echo showerror("FATAL ERROR in config.<br>" . implode("<br>\n", $aErrors));
} else {
    echo showok('OK, check was successfully finished.');
}

// do not enable - it shows passwords...
// echo 'DEBUG: <pre>' . print_r($aConfig, 1) . '</pre>';
