Skip to content
Snippets Groups Projects
Select Git revision
  • 01b609dd5efbc6f4a41e36b1e826d62b5d0b0b67
  • master default protected
  • simple-task/7248-eol-check-add-node-22
  • 6877_check_iml_deployment
4 results

check_docker_info

Blame
  • redirect.admin.class.php 9.34 KiB
    <?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
     * 2023-08-28  v1.8  ah  remove php warning if there is no config yet
     * 2024-10-04  v1.9  ah  php8 only: typed variables
     * 2025-01-13  v1.10 ah  fetch curl error
     */
    
    /**
     * Description of redirect
     *
     * @author axel
     */
    class redirectadmin extends redirect
    {
    
        /**
         * Get default curl options
         * @return array
         */
        protected function _getCurlOptions(): array
        {
            $aReturn = [
                CURLOPT_HEADER => true,
                CURLOPT_FOLLOWLOCATION => true,
                CURLOPT_RETURNTRANSFER => true,
                CURLOPT_USERAGENT => strip_tags($this->_app . ' ' . $this->_version),
                CURLOPT_VERBOSE => false,
                CURLOPT_ENCODING => 'gzip, deflate',  // to fetch encoding
                CURLOPT_HTTPHEADER => [
                    '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 => true,
                // CURLOPT_SSL_VERIFYPEER => false,
                CURLOPT_TIMEOUT => 5,
            ];
            return $aReturn;
        }
    
        /**
         * Make a single http(s) get request and return an array with response header, body, curl error info
         * @param string   $url          url to fetch
         * @param boolean  $bHeaderOnly  optional: true=make HEAD request; default: false (=GET)
         * @return array
         */
        public function httpGet(string $url, bool $bHeaderOnly = false): array
        {
            $aResult = [];
    
            $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);
    
            $sHeader = '';
            $sBody = '';
    
            if($bHeaderOnly){
                $sHeader = $res;
                $sBody = '';
            } else {
                $aResponse = explode("\r\n\r\n", $res, 2);
                list($sHeader, $sBody) = count($aResponse) > 1
                ? $aResponse
                : [$aResponse[0], ''];
            }
    
            $aResult = [
                'url' => $url,
                'response_header' => $sHeader,
                'response_body' => $sBody,
                // 'curlinfo' => curl_getinfo($ch),
                'curlerrorcode' => curl_errno($ch),
                'curlerrormsg' => curl_error($ch),
            ];
    
            curl_close($ch);
            return $aResult;
        }
    
        /**
         * Get html code for a response header of a request
         * 
         * @param array $aResponse  response array from httpGet() method
         * @return string
         */
        public function renderHttpResponseHeader(array $aResponse): string
        {
            $sHeader=$aResponse['response_header']."\r\n\r\n".$aResponse['response_body'];
    
            // $sReturn.="<pre>".print_r($aResponse, 1)."</pre>";
            $iJump = 0;
            $sBox = '';
            $sReturn = '';
    
            if ($aResponse['curlerrorcode']) {
                $sReturn .= '<br>'
                    .'<span class="status status-error">Request failed.</span>'
                    .'<pre>'
                    .'Curl error #'.$aResponse['curlerrorcode'] .':<br>'
                    . '<strong>'.$aResponse['curlerrormsg'].'</strong><br><br>'
                    .'</pre>'
                    .'🌐 <a href="https://curl.se/libcurl/c/libcurl-errors.html" target="_blank">Curl error codes</a>'
                ;
            } 
    
            $sUrl=$aResponse['url'];
            foreach(explode("\r\n\r\n",  $aResponse['response_header']."\r\n\r\n".$aResponse['response_body'] ) as $sBlock){
                if(strlen($sBlock)){
                    $iJump++;
    
                    // find http status
                    preg_match('/HTTP\/.* ([0-9]*) /', $sBlock, $aTmp);
                    // $sReturn.='<pre>'.print_r($aTmp, 1).'</pre>';
                    $iStatus=$aTmp[1] ?? '0';
    
                    $sStatus='';
                    if($iStatus>=200 && $iStatus<300){
                        $sStatus='status-ok';
                    } elseif($iStatus>=300 && $iStatus<400){
                        $sStatus='status-redirect';
                    } elseif($iStatus>=400 && $iStatus<500){
                        $sStatus='status-error';
                    } elseif($iStatus>=500 && $iStatus<600){
                        $sStatus='status-error';
                    }
    
                    // find location
                    preg_match('/Location: (.*)/i', $sBlock, $aTmp);
                    $sNextUrl=$aTmp[1] ?? '';
    
    
                    // modify lines in block
                    $sBlock = preg_replace('/(x-debug-.*)\\r/i', '<span class="debug">$1</span>', $sBlock);
                    $sBlock = preg_replace('/(location:.*)\\r/i', '<span class="location">$1</span>', $sBlock);
        
    
                    $sReturn.="<span class=\"status $sStatus\">$sUrl ($iStatus) </span><pre>$sBlock</pre>";
                    // $sReturn .= '<strong>'.$iJump.') HTTP status: '.$iStatus.' - '.$sUrl.'</strong><pre>'.$sBlock.'</pre>';
                    
    
                    $sWebhost=parse_url($sUrl, PHP_URL_HOST);
                    $sBox.="<div class=\"box $sStatus\">"
                        .$sWebhost.'<br>'
                        . $this->_getIp($sWebhost)
                        .'</div>';
    
                    if($sNextUrl){
                        $sBox.= " --- $iStatus ---&gt; ";
                        $sUrl=$sNextUrl;
                    }
    
                }
            }
            $iHops = $iJump-1;
            $sReturn = '<br>'.($iHops > 0
                ? 'Found hops: <strong>' . $iHops . '</strong>'
                . ($iHops > 1 ? '<span class="warning"> ⚠️ Verify your redirect to skip unneeded hops.</span>' : '') . '<br><br>'
                . '<div>'.$sBox.'</div><br><br><br>'
                : ''
            ) 
            
            . $sReturn;
    
            return $sReturn;
        }
    
        /**
         * Check if admin is enabled
         * 
         * @return bool
         */
        public function isEnabled(): bool
        {
            $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(string $sHostname): string
        {
            $sIp = gethostbyname($sHostname);
            return $sIp === $sHostname ? '' : $sIp;
        }
    
        /**
         * Get an array with all config entries in all json files
         * including some error checking
         * 
         * @return array
         */
        public function getHosts(): array
        {
            $aReturn = [];
            $aErrors = [];
            foreach (glob($this->sConfigDir . '/redirects_*.json') as $sFilename) {
                $sMyHost = str_replace(['redirects_', '.json'], ['', ''], basename($sFilename));
                $aReturn[$sMyHost] = [
                    'type' => 'config',
                    'file' => $sFilename,
                    'ip' => $this->_getIp($sMyHost),
                    'aliases' => [],
                    '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();
            if (is_array($aAliases) && count($aAliases)) {
                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] = [
                                '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;
        }
    
        function getTitle(): string
        {
            return 'Redirect :: admin <small>'.$this->_version.'</small>';
        }
    }