<?php
/**
 * @copyright (c) Kufer Software GmbH, Oderstraße 7, D-84453 Mühldorf
 */





class DebugOperations
{
  
  public static function backtrace()
  {
    $arr = debug_backtrace();
    $report = "<pre>\n";
    for ($j = 1; $j < count($arr); $j++) {
      $item = $arr[$j];
      $nextText = (isset($item['class']) ? $item['class'] . '::' : '') . $item['function'];
      $report .= 'Funktion: ' . $nextText;
      for ($i = 0; $i < ceil(((48 - StringOperations::strlen($nextText)) / 4)); $i++) {
        $report .= "\t";
      }

      $nextText = isset($item['file']) ? $item['file'] : '';
      $report .= ' aufgerufen in ' . $nextText;
      
      for ($i = 0; $i < ceil(((72 - StringOperations::strlen($nextText)) / 4)); $i++) {
        $report .= "\t";
      }
      if (isset($item['line'])) {
        $report .= ' Zeile ' . $item['line'] . "\n";
      }
      
      
    }
    $report .= "\n</pre>\n\n";

    return $report;
  }

  
  public static function kuferInlineLog($pMessage)
  {
    if (self::isKuferRequest()) {
      echo '<span style="color: red">' . $pMessage . '</span>';
    }
  }

  public static function isKuferRequest()
  {
    return true;
    $remoteAddress = filter_input(INPUT_SERVER, 'REMOTE_ADDR');

    return $remoteAddress === STATIC_IP || $remoteAddress === STATIC_IP2;
  }

  
  public static function kuferInlineVarDump($pObj)
  {
    self::kuferInlineLog(self::varDump($pObj));
  }

  
  public static function varDump($pVar)
  {
    ob_start();
    var_dump($pVar);
    $content = ob_get_contents();
    ob_end_clean();

    return $content;
  }

  public static function echoExt($pMsg)
  {
    $arr = debug_backtrace();
    $item = $arr[0];
    echo $item['file'] . ' ' . $item['line'] . ': ' . $pMsg . "\n";
  }

  
  public static function kuferVarDumpKomplett($pMessage)
  {
    if (self::isKuferRequest()) {
      $thisdebug = new DebugOperations();
      $debugbacktrace = debug_backtrace()[1];
      
      $result = '<small>' . $debugbacktrace['file'] . ':' . $debugbacktrace['line'] . ':</small><br>'
        . '<small>' . $debugbacktrace['class'] . $debugbacktrace['type'] . $debugbacktrace['function'] . ':</small><br>'
        . $thisdebug->getSummaryDetails($thisdebug, $pMessage, '');


      echo '<pre>' . $result . '</pre>';
    }
  }

  
  public function getSummaryDetails(DebugOperations $thisdebug, $items, string $key)
  {
    $typausgabe = $this->getTypAusgabe($items);
    $key = $key == '' ? '' : "'$key' <span style='color: #888a85'>=&gt;</span>";
    $itemtyp = gettype($items);
    if (($itemtyp == 'array' && !empty($items)) || $itemtyp == 'object') {
      $result = "<summary style='cursor: pointer;'>$key $typausgabe</summary>";
      foreach ($items as $key => $item) {
        $result .= $thisdebug->getSummaryDetails($thisdebug, $item, $key);
      }

      return "<details style='padding-left: 2em;'>$result</details>";
    }

    return "<span style='padding-left: 2em;'>$key $typausgabe</span><br>";
  }

  private function getTypAusgabe($item)
  {
    $itemtyp = gettype($item);
    switch ($itemtyp) {
      default:
        return $itemtyp . ' ' . $item;
      case 'string':
        return 'string <span style="color: #cc0000; padding: 0;">\'' . $item . '\'</span>';
      case 'bool':
      case 'boolean':
        return 'boolean <span style="color: #75507b">' . ($item ? 'true' : 'false') . '</span>';
      case 'integer':
      case 'int':
        return 'int <span style="color: #4e9a06">' . $item . '</span>';
      case 'float':
      case 'double':
        return $itemtyp . ' ' . '<span style="color: #f57900">' . $item . '</span>';
      case 'NULL':
      case 'null':
        return '<span style="color: #3465a4">null</span>';
      case 'array':
      case 'Array':
        return '<b>array</b> <i>(' . count($item) . ')</i>';
      case 'object':
        return '<b>object</b> <i>(' . get_class($item) . ')[' . count((array)$item) . ']</i>';
    }
  }

  
  public static function getBackTrace($expandObjects = false, $expandHtml = false)
  {
    $ret = "callstack:\n";
    $backtrace = debug_backtrace();
    $backtrace = array_slice($backtrace, 1);
    $backtrace = array_slice(array_reverse($backtrace), -7);
    $count = 1;
    foreach ($backtrace as $trace) {
      $ret .= \StringOperations::getAnzahlTabs($count) . 'Function: ' . self::getVarString($trace['object'] ?? '', $expandObjects, $expandHtml) . @$trace['type'] . @$trace['function'] . "\n";
      $ret .= \StringOperations::getAnzahlTabs($count) . 'Arguments: ' . self::getVarString($trace['args'] ?? '', $expandObjects, $expandHtml) . "\n";
      $ret .= \StringOperations::getAnzahlTabs($count) . 'File: ' . @$trace['file'] . ':' . @$trace['line'] . "\n";
      ++$count;
    }

    return $ret;
  }

  
  public static function getBacktraceFromException(Exception $exception, $expandObjects = false, $expandHtml = false)
  {
    $ret = "callstack:\n";

    $backtrace = $exception->getTrace();
    $backtrace = array_reverse($backtrace);

    $count = 1;
    foreach ($backtrace as $trace) {
      $ret .= \StringOperations::getAnzahlTabs($count) . 'Typ des Objekts, auf dem der Aufruf stattfand: ' . @$trace['class'] . "\n";
      $ret .= \StringOperations::getAnzahlTabs($count) . 'Typ des Aufrufs: ' . @$trace['type'] . "\n";
      $ret .= \StringOperations::getAnzahlTabs($count) . 'Funktion, die aufgerufen wurde: ' . @$trace['function'] . "\n";
      $ret .= \StringOperations::getAnzahlTabs($count) . 'Argumente, die der Funktion uebergeben wurden : ' . self::getVarString(@$trace['args'], $expandObjects, $expandHtml) . "\n";
      $ret .= \StringOperations::getAnzahlTabs($count) . 'Datei, wo der Aufruf stattfand: ' . @$trace['file'] . "\n";
      $ret .= \StringOperations::getAnzahlTabs($count) . 'Zeile, wo der Aufruf stattfand: ' . @$trace['line'] . "\n";

      ++$count;
    }

    return $ret;
  }

  
  public static function getVollstaendigeAufgerufeneURL()
  {
    $protocol = RequestOperations::getHttpProtocolPrefix();

    return $protocol . ($_SERVER['HTTP_HOST'] ?? '') . RequestOperations::getPhpSelf() . '?' . ($_SERVER['QUERY_STRING'] ?? '');
  }

  public static function getUrlWithoutParams()
  {
    $protocol = RequestOperations::getHttpProtocolPrefix();

    return $protocol . $_SERVER['HTTP_HOST'];
  }

  
  public static function getVarString($var, $expandObjects = false, $expandHtml = false)
  {
    $ret = '';

    if (is_array($var)) {
      foreach ($var as $key => $val) {
        $ret .= ', ' . $key . ' => ' . self::getVarString($val, $expandObjects, $expandHtml);
      }
      $ret = StringOperations::substr($ret, 2);
    } elseif (is_object($var)) {
      $array = (array)$var;
      if ($expandObjects) {
        $ret = get_class($var) . '{' . self::getVarString($array, $expandObjects, $expandHtml) . '}';
      } else {
        if (count($array) > 0) {
          $ret = get_class($var) . '{...}';
        } else {
          $ret = get_class($var) . '{}';
        }
      }
    } elseif (is_string($var)) {
      if (StringOperations::startsWith($var, '<')) {
        if ($expandHtml) {
          $ret = $var;
        } else {
          $ret = '<htmlcode>';
        }
      } else {
        $ret = StringOperations::getReadableString($var);
      }
    } else {
      $ret = $var;
    }

    return $ret;
  }

  
  public static function writeLogDatei($pErrorMsg)
  {
    $allgsettings = AllgSettingsAPI::getAllgSettings();
    $msg = 'Es ist ein kritischer Fehler aufgetreten: ' . $pErrorMsg;

    $logdirname = ConstantOperations::getPathForLog();

    $filename = $logdirname . 'log.txt';
    if (!file_exists($logdirname)) { 
      if (!@mkdir($logdirname)) {
        die('Das Log Verzeichnis existiert nicht und es konnte auch '
               . 'nicht angelegt werden!<br />'
                . 'Bitte geben Sie einem Administrator Bescheid (s. '
                . '<a href=' . $allgsettings->impressum . '>Impressum</a>).');
      } else { 
        
        if (!file_exists($logdirname . '.htaccess')) {
          $htaccess = "AuthType Basic\r\nAuthName \"Logs\"\r\n";
          $htaccess .= 'AuthUserFile ' . $logdirname . ".htpasswd \r\n";
          $htaccess .= "require user su\r\n<Files *.txt>\r\nrequire user su\r\n</Files>";
          ($htaccessHandle = @fopen($logdirname . '.htaccess', 'w'))
                       or die('Kann Zugriffsdatei nicht öffnen/schreiben.');
          fwrite($htaccessHandle, $htaccess);
          fclose($htaccessHandle);
        }
        
        if (!file_exists($logdirname . '.htpasswd')) {
          $htpasswd = 'su:su';
          ($htpasswdHandle = @fopen($logdirname . '.htpasswd', 'w')) or die('Kann Passwort Datei nicht öffnen/schreiben.');
          fwrite($htpasswdHandle, $htpasswd);
          fclose($htpasswdHandle);
        }
      }
    }
    ($datei = @fopen($filename, 'a')) or die('Die Logdatei konnte nicht geöffnet'
               . ' werden.<br />Bitte geben Sie einem Administrator bescheid (s. '
               . '<a href=' . $allgsettings->impressum . '>Impressum</a>).');
    fwrite($datei, date('Y.M.d H:i:s: ') . "$msg\r\n");
    fclose($datei);
  }

  
  public static function sendSqlErrorMail($pErrorMsg, $pSql = '', $pDbTyp = '')
  {
    
    if (false === StringOperations::strpos($pErrorMsg, 'Error #1146:') && false === StringOperations::strpos($pErrorMsg, 'Error (1146):')) {
      $settings = AllgSettingsAPI::getAllgSettings();

      $msg = "Datenbank ($pDbTyp) Fehler!\n";
      $msg .= 'Einrichtungsname: ' . $settings->vhsname . "\n";
      $msg .= 'Fehler: ' . $pErrorMsg;
      $msg .= 'SQL Statement bei dem der Fehler auftrat: ' . StringOperations::getReadableString($pSql) . "\n";
      $msg .= 'url: ' . DebugOperations::getVollstaendigeAufgerufeneURL() . "\n";

      self::sendErrorMail($msg, 1);
    }
  }

  public static function sendDmzErrorMail($pErrorMsg)
  {
    $settings = AllgSettingsAPI::getAllgSettings();

    $msg = 'Einrichtungsname: ' . $settings->vhsname . "\n";
    $msg .= 'DMZ-Fehler: ' . $pErrorMsg;
    if (DBWorkBASysSettings::isMVHS()) {
      $msg .= 'Server: ' . $settings->dmzServer;
    }

    self::sendErrorMail($msg, 2);
  }

  
  public static function sendErrorMail($pErrorMsg, $pType)
  {
    $settings = AllgSettingsAPI::getAllgSettings();

    $fw = new FileWorkErrorMail();
    $fehlermailZuletztVersendet = $fw->readFehlermailZuletztVersendetArray();

    if ($pType == 1) {
      $fehlerTyp = 'SQL';
    } else {
      $fehlerTyp = 'DMZ';
    }

    self::loggFehlermailZuletztVersendet($fehlerTyp, $fehlermailZuletztVersendet);

    if (SessionOperations::getVarValueIntern($fehlerTyp . 'ErrorMailVersendet') == '' && ($settings->fehlerMailAnEinrichtung || $settings->fehlerMailAnEmail || $settings->fehlerMailAnKubus)) {
      SessionOperations::setVarValueIntern($fehlerTyp . 'ErrorMailVersendet', 'true');

      $offset = 600;
      $fehlermailZuletztVersendetAusgelesen = isset($fehlermailZuletztVersendet['fehlerMailZuletztVersendet' . $fehlerTyp]) ? $fehlermailZuletztVersendet['fehlerMailZuletztVersendet' . $fehlerTyp] : 0;
      if ($fehlermailZuletztVersendetAusgelesen > (time() - $offset)) {
        $zuletztVersendet = round((time() - $fehlermailZuletztVersendetAusgelesen) / 60);
        Logger::logg("Die $fehlerTyp-Fehlermail wurde bereits vor ca. $zuletztVersendet Minuten versendet (Abstand in denen $fehlerTyp-Fehlermails versendet werden: " . round($offset / 60) . ' Minuten)!', 5);

        return;
        
        
        
      }

      Logger::logg("E-Mail:\n" . $pErrorMsg, 500);

      $emailAnEinrichtung = new \Kufer\Mail\EMail\EMailPlaintext($settings->fehlerMailBetreff !== '' ? $settings->fehlerMailBetreff : 'Ein Fehler ist aufgetreten', $pErrorMsg);

      $sender = \Kufer\Mail\Sender\EMailSenderFactory::create();

      $versendet = false;
      $empfaengerliste = array();
      if ($settings->fehlerMailAnEinrichtung) {
        $mailok = $sender->informEinrichtung($emailAnEinrichtung)->hasSentAnyMails();
        $versendet = $versendet || $mailok;
        if ($mailok) {
          $empfaengerliste[] = 'Einrichtung: ' . $settings->vhsemail;
        }
      }
      if ($settings->fehlerMailAnEmail) {
        $mailok = $sender->sendFromEinrichtung(
          $emailAnEinrichtung,
          array(new \Kufer\Mail\Address\EMailAddress('', $settings->fehlerMailAdresse)),
          'Einrichtung'
        )->hasSentAnyMails();
        $versendet = $versendet || $mailok;
        if ($mailok) {
          $empfaengerliste[] = 'Email an: ' . $settings->fehlerMailAdresse;
        }
      }
      if ($settings->fehlerMailAnKubus) {
        $emailAnUns = new \Kufer\Mail\EMail\EMailPlaintext(
          '[WEB][FEHLER] [' . $fehlerTyp . '] ' . $settings->vhsname,
          $pErrorMsg . \DebugOperations::getBackTrace()
        );

        $mailok = $sender->sendFromEinrichtung(
          $emailAnUns,
          array(new \Kufer\Mail\Address\EMailAddress('Kubus', KUBUS_FEHLERMAIL_ADRESSE)),
          'Kubus'
        )->hasSentAnyMails();

        $versendet = $versendet || $mailok;
        if ($mailok) {
          $empfaengerliste[] = 'Kubus: ' . KUBUS_FEHLERMAIL_ADRESSE;
        }
      }

      Logger::logg('Fehlermail (' . implode(',', $empfaengerliste) . ')' . ($versendet ? '' : 'nicht') . ' erfolgreich versendet!', 500);

      if ($versendet) {
        $fw = new FileWorkErrorMail();
        $fw->writeFehlermailZuletztVersendetArray($fehlermailZuletztVersendet, $fehlerTyp);
      } else {
        Logger::logg("E-Mail für $fehlerTyp-Fehler konnte nicht versendet werden!", 500);
      }
    }
  }

  private static function loggFehlermailZuletztVersendet($fehlerTyp, $fehlermailZuletztVersendet)
  {
    if (!array_key_exists('fehlerMailZuletztVersendet' . $fehlerTyp, $fehlermailZuletztVersendet)) {
      Logger::logg("$fehlerTyp-Fehlermail noch nie versendet", 5);
    } else {
      Logger::logg("$fehlerTyp-Fehlermail zuletzt versendet um " . date('H:i', $fehlermailZuletztVersendet['fehlerMailZuletztVersendet' . $fehlerTyp]) . ' Uhr', 5);
    }
  }

  
  public static function showUserMessageAndDie()
  {
    $message = "\nEin fataler Fehler ist aufgetreten\n\n" . DebugOperations::getBackTrace();
    Logger::logg($message, 999);

    $allgsettings = AllgSettingsAPI::getAllgSettings();
    $userMsg = "<div class='hauptseite' style='border-style: solid; border-width: 0.2em; padding: 0.5em; position: absolute; z-index: 255;'>\n";
    $userMsg .= 'Es ist ein interner Fehler aufgetreten.<br />';
    $userMsg .= 'Bitte versuchen Sie es später erneut, oder wenden Sie sich an die Verantwortlichen (s. ';
    $userMsg .= '<a href=' . CleanOperations::cleanStringForHtml($allgsettings->impressum) . '>Impressum</a>).';
    header('HTTP/1.1 500 Internal Server Error');
    die($userMsg);
  }

  
  public static function getCurrentTime()
  {
    list($usec, $sec) = explode(' ', microtime());

    return \DateTimeOperations::datefmt('yyyy.MM.dd. HH:mm:ss:' . StringOperations::substr($usec, 2, -2), $sec);
  }
}