diff --git a/public_html/admin/functions.js b/public_html/admin/functions.js new file mode 100644 index 0000000000000000000000000000000000000000..17f6b4b30d94b7017868626312ef86b47c4b3568 --- /dev/null +++ b/public_html/admin/functions.js @@ -0,0 +1,64 @@ +/** + * ====================================================================== + * + * IML REDIRECT :: JAVASCRIPT FUNCTIONS + * + * ---------------------------------------------------------------------- + * 2022-05-23 ah v0.1 initial version + * ====================================================================== + */ + + +// ---------------------------------------------------------------------- +// CONFIG +// ---------------------------------------------------------------------- + +let divOut="divoverlay"; + +// ---------------------------------------------------------------------- +// FUNCTIONS +// ---------------------------------------------------------------------- + +/** + * show given html code in overlay + * @param {string} body html code to display + */ +async function show(body){ + oDiv=document.getElementById(divOut); + oDiv.innerHTML='<div>'+body+'</div>'; + oDiv.style.display='block'; +} + +/** + * show content of a url in the overlay + * @param {object} oLink link object; in a tag use this to reference itself + */ +async function showInOverlay(oLink){ + show('<h2>Please wait ...</h2><p>Requesting data...</p>'); + let response = await fetch(oLink.href); + let body = await response.text(); // read response body as text + + + if (response.ok) { + show(body); + } else { + show("HTTP-Error: " + response.status); + } + +} + + + +// ---------------------------------------------------------------------- +// page init +// ---------------------------------------------------------------------- + +// init datatable +$(document).ready( function () { + $('.mydatatable').DataTable({ + "lengthMenu": [[10, 25, 50, 100, -1], [10, 25, 50, 100, "All"]], + stateSave: true + }); +} ); + +// ---------------------------------------------------------------------- \ No newline at end of file diff --git a/public_html/admin/index.php b/public_html/admin/index.php index e4725e4c868e8890487f1af32f8aa513f1704ace..4a33f0cce1cc22a2aaea8e08e0546c991ed97fcc 100644 --- a/public_html/admin/index.php +++ b/public_html/admin/index.php @@ -20,6 +20,24 @@ $oR=new redirectadmin(); $sHtml=''; $sErrors=''; +$aIco=[ + 'h1'=>'β©', + + 'h2_head'=>'βοΈ', + 'h2_err'=>'π', + 'h2_config'=>'π οΈ', + 'h2_file'=>'π', + + 'ip_ok'=>'π’', + 'ip_warn'=>'π ', + 'ip_err'=>'β', + + 'type_config'=>'π·', + 'type_alias'=>'β»οΈ', + + 'url'=>'π', +]; + // ---------------------------------------------------------------------- // FUNCTIONS // ---------------------------------------------------------------------- @@ -36,9 +54,34 @@ if (!$oR->isEnabled()){ $sHtml.='<div class="error">Admin is disabled.</div>'; } else { - $sUrl=(isset($_GET['url']) && $_GET['url']) ? $sUrl=$_GET['url'] : ''; - $sMyIp=gethostbyname($_SERVER['SERVER_NAME']); + // ---------- return content for ajax requests + + // ---------- TEST URL + $sUrl=(isset($_GET['url']) && $_GET['url']) ? $_GET['url'] : ''; + + if ($sUrl){ + $sResult=$oR->httpGet($sUrl.'?debugredirect=1',1); + echo '<h2>Response of a http HEAD request to '.$aIco['url'].' <a href="'.$sUrl.'">'.$sUrl.'</a></h2>' + . $oR->renderHttpResponseHeader($sResult, 1) + ; + return true; + } + # ---------- return content for ajax requests + $sCfgfile=(isset($_GET['cfgfile']) && $_GET['cfgfile']) ? $_GET['cfgfile'] : ''; + if($sCfgfile){ + $sFilename=__DIR__.'/../../config/'.$sCfgfile; + echo '<h2>'.$aIco['h2_file'].' File: '.htmlentities($sCfgfile).'</h2>' + . (file_exists($sFilename) + ? '<pre>'. file_get_contents($sFilename).'</pre>' + : '<div class="error">ERROR: config file was not found.</div>' + ) + ; + exit(0); + } + + + $sMyIp=gethostbyname($_SERVER['SERVER_NAME']); if(!$sMyIp){ $sErrors.='<li>Ip address of current host ['.$_SERVER['SERVER_NAME'].'] was not found.</li>'; } @@ -50,7 +93,7 @@ if (!$oR->isEnabled()){ // ---------- SHOW ERRORS if(count($aHosts['_errors'])) { - $sErrors.= '<li>' . implode('</li></li>', $aHosts['_errors']).'</li>'; + $sErrors.= '<li>' . implode('</li><li>', $aHosts['_errors']).'</li>'; } unset($aHosts['_errors']); @@ -58,16 +101,17 @@ if (!$oR->isEnabled()){ $sHtml.=' - <h2>βοΈ Http head tester</h2> + <!-- + <h2>'.$aIco['h2_head'].' Http head tester</h2> <div class="content"> <form> - π <input type="text" name="url" size="100" value="'.$sUrl.'" placeholder="Enter url or click a link in the table below."/> + '.$aIco['url'].' <input type="text" name="url" size="100" value="'.$sUrl.'" placeholder="Enter url or click a link in the table below."/> <button>Http HEAD</button> </form> </div> <br> - - <h2>π οΈ Domains and their redirects</h2> + --> + <h2>'.$aIco['h2_config'].' Domains and their redirects</h2> <div class="content"> <table class="mydatatable"><thead> @@ -83,20 +127,30 @@ if (!$oR->isEnabled()){ </thead><tbody>'; foreach($aHosts as $sHost => $aCfg){ $sTdFirst='<tr class="cfgtype-'.$aCfg['type'].'">' - .'<td>π· <a href="?url=http://'.$sHost.'/" title="click to test http://'.$sHost.'/">'.$sHost.'</a></td>' + .'<td>' + .'<span style="display: none">'.$sHost.'</span>' + .$aIco['type_'.$aCfg['type']] + .' <a href="?url=http://'.$sHost.'/" title="click to test http://'.$sHost.'/" onclick="showInOverlay(this); return false;">'.$sHost.'</a></td>' .'<td>' .($aCfg['ip'] ? ($aCfg['ip']===$sMyIp - ? '<span title="">π’ '.$aCfg['ip']. '</span>' - : '<span title="Warning: this is not the ip address of the current host ('.$sMyIp.')">π '.$aCfg['ip']. '</span>' + ? '<span title="">'.$aIco['ip_ok'].' '.$aCfg['ip']. '</span>' + : '<span title="Warning: this is not the ip address of the current host ('.$sMyIp.')">'.$aIco['ip_warn'].' '.$aCfg['ip']. '</span>' ) - : '<span class="error">βERROR: unknown host</span>') + : '<span class="error">'.$aIco['ip_err'].' ERROR: unknown host</span>') .'</td>' - .'<td>'.$aCfg['type'].'</td>' + .'<td>' + .($aCfg['type']=="config" + ? '<a href="?cfgfile=redirects_'.$sHost.'.json" onclick="showInOverlay(this); return false;" title="show config for host '.$sHost.'">'.$aCfg['type'].'</a> ' + : $aCfg['type'] + ) + . '</td>' ; + /* if(!$aCfg['ip']){ $sErrors.='<li>Host was not found in DNS: '.$sHost.'</li>'; } + */ if (isset($aCfg['redirects'])){ $iCount=0; foreach(['direct', 'regex'] as $sType){ @@ -106,10 +160,13 @@ if (!$oR->isEnabled()){ $sHtml.=$sTdFirst .'<td class="type-'.$sType.'">'.$sType.'</td>' .'<td class="type-'.$sType.'">' - .($sType == 'direct' ? '<a href="?url=http://'.$sHost.'/'.$sFrom.'" title="click to test http://'.$sHost.'/'.$sFrom.'">'.$sFrom.'</a>' : $sFrom) + .($sType == 'direct' + ? '<a href="?url=http://'.$sHost.'/'.$sFrom.'" title="click to test http://'.$sHost.'/'.$sFrom.'" onclick="showInOverlay(this); return false;">/'.$sFrom.'</a>' + : $sFrom + ) .'</td>' .'<td class="http-'.$aTo['code'].'">'.$aTo['code'].'</td>' - .'<td>π <a href="?url='.$aTo['target'].'" title="click to test '.$aTo['target'].'">'.$aTo['target'].'</a></td>' + .'<td>'.$aIco['url'].' <a href="?url='.$aTo['target'].'" title="click to test '.$aTo['target'].'" onclick="showInOverlay(this); return false;">'.$aTo['target'].'</a></td>' .'</tr>'; } } @@ -129,18 +186,11 @@ if (!$oR->isEnabled()){ */ ; - // ---------- TEST URL - if ($sUrl){ - $sResult=$oR->httpGet($sUrl.'?debugredirect=1',1); - $sHtml.= '<div class="overlay" onclick="this.style.display=\'none\';"><div>' - . '<h2>π <a href="'.$sUrl.'">'.$sUrl.'</a></h2> (click to open)<br><br>' - . 'π Http response header:<br><br>'.$oR->renderHttpResponseHeader($sResult, 1) - . '</div></div>' - ; - } + + $sErrors = $sErrors - ? '<h2>π Found errors</h2>' + ? '<h2>'.$aIco['h2_err'].' Found errors</h2>' .'<div class="content">' .'<ol class="error">' .$sErrors @@ -163,17 +213,14 @@ if (!$oR->isEnabled()){ <link rel="stylesheet" href="main.css"> </head> <body> - <h1>β© <a href="?">Redirects :: admin</a></h1> + <h1><?php echo $aIco['h1']?> <a href="?">Redirects :: admin</a></h1> <?php echo $sErrors . $sHtml; ?> + <div id="divoverlay" class="overlay" onclick="this.style.display='none';"></div> + <script type="text/javascript" src="functions.js"></script> <script> - $(document).ready( function () { - $('.mydatatable').DataTable({ - "lengthMenu": [[10, 25, 50, 100, -1], [10, 25, 50, 100, "All"]], - stateSave: true - }); - } ); + </script> </body> </html> diff --git a/public_html/admin/main.css b/public_html/admin/main.css index e77811b8d04d7d90c7603be3a9c0dcc013da4978..55c639c29df54fd87fddcd6416395acebf62b5ca 100644 --- a/public_html/admin/main.css +++ b/public_html/admin/main.css @@ -3,9 +3,11 @@ body{background: #f8f8f8; color: #234; font-family: arial; margin: 0;} h1{background:rgba(0,0,0,0.05); margin: 0 0 1em;; padding: 0.5em;} h1 a{color:#234; text-decoration: none;} h2{background:rgba(0,0,0,0.02); color:#458; margin: 1em 0 0.5em; border-top: 2px solid #fff; border-left: 5px solid #fff; border-top-left-radius: 0.5em; padding: 0.5em; } -h2 a{color:#458; text-decoration: none; } + pre{background: rgba(0,0,0,0.02);padding: 0.3em 1em; border: 1px solid rgba(0,0,0,0.1); margin-bottom: 2em;} +tr:hover{background: #f4f0f8 !important;} + .content{margin: 0 1em;} .error{background: #fcc;} @@ -24,5 +26,6 @@ pre{background: rgba(0,0,0,0.02);padding: 0.3em 1em; border: 1px solid rgba(0,0, .location{background:#fec;} .debug{color:#197;} -.overlay{position: fixed; margin: 0; width: 100%; height: 100%; top: 0; left: 0; background: rgba(0,0,0,0.3);overflow: scroll;} +.overlay{position: fixed; margin: 0; width: 100%; height: 100%; top: 0; left: 0; background: rgba(0,0,0,0.3);overflow: scroll; display: none;} .overlay>div{margin: 3% 10%; background: #fff; padding: 1em;box-shadow: 0 0 3em #000; } + diff --git a/public_html/classes/redirect.admin.class.php b/public_html/classes/redirect.admin.class.php index 190a8a7f87c4dcb15260bc6ca6cdc4857df2db4e..333cea8e67862ec731b8568b7e4c040b8423fa4c 100644 --- a/public_html/classes/redirect.admin.class.php +++ b/public_html/classes/redirect.admin.class.php @@ -15,6 +15,7 @@ require_once 'redirect.class.php'; * ---------------------------------------------------------------------- * 2020-05-11 v1.4 ah rewrite as class * 2022-02-03 v1.5 ah add method isEnabled + * 2022-05-23 v1.6 ah add http head check+render output; */ /** @@ -119,14 +120,19 @@ class redirectadmin extends redirect { return file_exists($sFile2Enable); } - + /** + * get ip address of a given hostname as ip (string) or false + * @return string|bool + */ protected function _getIp($sHostname){ $sIp=gethostbyname($sHostname); return $sIp===$sHostname ? false : $sIp; } /** - * get an array with all config entries in all json + * get an array with all config entries in all json files + * including some error checking + * @return array */ public function getHosts(){ $aReturn = array(); @@ -140,11 +146,14 @@ class redirectadmin extends redirect { 'aliases'=>array(), 'redirects'=>json_decode(file_get_contents($sFilename), 1), ); + if (!$aReturn[$sMyHost]['ip']){ + $aErrors[]=basename($sFilename).': The hostname was not found in DNS: '.$sMyHost; + } } $aAliases=$this->_getAliases(); foreach($aAliases as $sAlias=>$sConfig){ if(isset($aReturn[$sAlias])){ - $aErrors[]="alias.json: Alias [$sAlias] was set already - ".print_r($aReturn[$sAlias], 1); + $aErrors[]="alias.json: A configuration for alias [$sAlias] is useless. There exists a file redirects_{$sAlias}.json (which has priority)."; } else { if(!isset($aReturn[$sConfig])){ $aErrors[]="alias.json: [$sAlias] points to a non existing host [$sConfig] - a file redirects_$sConfig.yml does not exist."; @@ -155,6 +164,9 @@ class redirectadmin extends redirect { 'target'=>$sConfig, 'ip'=> $this->_getIp($sAlias), ); + if (!$aReturn[$sAlias]['ip']){ + $aErrors[]='alias.json: The hostname was not found in DNS: '.$sAlias; + } } } }