<?php require_once 'redirect.class.php'; /** * ---------------------------------------------------------------------- * _____ __ __ _ _____ _ _ _ * |_ _| \/ | | | __ \ | (_) | | * | | | \ / | | | |__) |___ __| |_ _ __ ___ ___| |_ * | | | |\/| | | | _ // _ \/ _` | | '__/ _ \/ __| __| * _| |_| | | | |____ | | \ \ __/ (_| | | | | __/ (__| |_ * |_____|_| |_|______| |_| \_\___|\__,_|_|_| \___|\___|\__| * * ---------------------------------------------------------------------- * Loads a config json from outside webroot and makes a 3xx redirect * if the definition exists * ---------------------------------------------------------------------- * 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; * 2022-05-31 v1.7 ah optical changes */ /** * Description of redirect * * @author axel */ class redirectadmin extends redirect { protected function _getCurlOptions(){ $aReturn=array( CURLOPT_HEADER => true, CURLOPT_FOLLOWLOCATION => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_USERAGENT => strip_tags($this->sAbout), CURLOPT_VERBOSE => false, CURLOPT_ENCODING => 'gzip, deflate', // to fetch encoding CURLOPT_HTTPHEADER => array( 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8', 'Accept-Language: en', 'DNT: 1', ), // TODO: this is unsafe .. better: let the user configure it CURLOPT_SSL_VERIFYHOST => false, CURLOPT_SSL_VERIFYPEER => false, CURLOPT_TIMEOUT => 5, ); return $aReturn; } /** * make a single http(s) get request and return the response body * @param string $url url to fetch * @param boolean $bHeaderOnly optional: true=make HEAD request; default: false (=GET) * @return string */ public function httpGet($url, $bHeaderOnly = false) { $ch = curl_init($url); foreach ($this->_getCurlOptions() as $sCurlOption=>$sCurlValue){ curl_setopt($ch, $sCurlOption, $sCurlValue); } if ($bHeaderOnly) { curl_setopt($ch, CURLOPT_HEADER, 1); curl_setopt($ch, CURLOPT_NOBODY, 1); } $res = curl_exec($ch); curl_close($ch); return ($res); } public function renderHttpResponseHeader($sHeader){ $sReturn=$sHeader; if(!$sReturn){ $sReturn='<pre><span class="status status-error">Request failed. </span><br>' .'No data... no response.<br>' .'Maybe ... ' .'<ul>' .'<li>the nostname does not exist ... </li>' .'<li>or there is a network problem ... or </li>' .'<li>the webservice on the target system does not run.</li>' .'</ul>' .'</pre>' ; } else { $sReturn=preg_replace('/(HTTP.*)\\r/', '</pre><pre><strong>$1</strong>', $sReturn); $sReturn=preg_replace('/(HTTP.*200.*)/', '<span class="status status-ok">$1</span>', $sReturn); $sReturn=preg_replace('/(HTTP.*30.*)/', '<span class="status status-redirect">$1</span>', $sReturn); $sReturn=preg_replace('/(HTTP.*40.*)/', '<span class="status status-error">$1</span>', $sReturn); $sReturn=preg_replace('/(HTTP.*50.*)/', '<span class="status status-error">$1</span>', $sReturn); $sReturn=preg_replace('/\ ([1-5][0-9][0-9])\ /', ' <span class="statuscode">$1</span> ', $sReturn); $sReturn=preg_replace('/(x-debug-.*)\\r/i', '<span class="debug">$1</span>', $sReturn); $sReturn=preg_replace('/(location:.*)\\r/i', '<span class="location">$1</span>', $sReturn); $sReturn.='</pre>'; preg_match_all('/(HTTP\/.*)/i', $sReturn, $aTmp); // $sReturn.=print_r($aTmp, 1); $iHops=(count($aTmp[0])-1); $sReturn=($iHops>0 ? 'Found hops: <strong>'.$iHops.'</strong>' .($iHops>1 ? ' <span class="warning"> ⚠️ Verify your redirect to skip unneeded hops.</span>' : '' ).'<br><br>' : '' ).$sReturn ; } return $sReturn; } /** * check if admin is enabled * @return bool */ public function isEnabled(){ $sFile2Enable=__DIR__ . '/'.basename(__FILE__).'_enabled.txt'; 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 files * including some error checking * @return array */ public function getHosts(){ $aReturn = array(); $aErrors = array(); foreach(glob($this->sConfigDir . '/redirects_*.json') as $sFilename){ $sMyHost= str_replace(array('redirects_', '.json'), array('',''), basename($sFilename)); $aReturn[$sMyHost]=array( 'type'=>'config', 'file'=>$sFilename, 'ip'=> $this->_getIp($sMyHost), '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: 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."; } else { $aReturn[$sConfig]['aliases'][]=$sAlias; $aReturn[$sAlias]=array( 'type'=>'alias', 'target'=>$sConfig, 'ip'=> $this->_getIp($sAlias), ); if (!$aReturn[$sAlias]['ip']){ $aErrors[]='alias.json: The hostname was not found in DNS: '.$sAlias; } } } } $aReturn['_errors']=$aErrors; ksort($aReturn); return $aReturn; } }