<?php
  /****** SETUP FOR POSSIBLE COMMANDLINE USE *******/
  // EdM 2015-11-13: Setup variables for commandline usage
  if(php_sapi_name() === "cli") {
    $_SERVER['DOCUMENT_ROOT'] = getcwd();
  }

  /****** LOG REQUESTS FOR DEBUGGING (uncomment the line below to make this effective) *******/
  // $log_requests = 1; // log all requests in file entry.log
  if(isset($log_requests) && $log_requests){
    $fh = fopen ("/tmp/entry.log","a");
    fwrite($fh, "REQUEST\n");
    fwrite($fh, "  DOCUMENT_ROOT         : $_SERVER[DOCUMENT_ROOT]\n");
    if(isset($_SERVER['REQUEST_URI']))
      fwrite($fh, "  REQUEST_URI           : $_SERVER[REQUEST_URI]\n");
    if(isset($_SERVER['QUERY_STRING']))
      fwrite($fh, "  QUERY_STRING          : $_SERVER[QUERY_STRING]\n");
    if(isset($_SERVER['HTTP_REFERER']))
      fwrite($fh, "  HTTP_REFERER          : $_SERVER[HTTP_REFERER]\n");
    if(isset($_SERVER['REDIRECT_URL']))
      fwrite($fh, "  REDIRECT_URL          : $_SERVER[REDIRECT_URL]\n");
    if(isset($_SERVER['REDIRECT_QUERY_STRING']))
      fwrite($fh, "  REDIRECT_QUERY_STRING : $_SERVER[REDIRECT_QUERY_STRING]\n");
    fclose($fh);
  }

  /****** INCLUDE GLOBAL VARIABLES *******/
  // EdM: 2025-02-13: move cms_globals to the cms directory, instead of v2.7
  // require_once($_SERVER['DOCUMENT_ROOT']."/_cms/cms_globals.inc");
  require_once(realpath(__DIR__.'/../cms_globals.inc'));

  /****** AUTOLOAD REQUIRED CLASSES AUTOMAGICALLY *******/
  // IMPORTANT: Name the file after the classname and place it in the classes directory!!!!!
  spl_autoload_register('_cms_autoload');

  function _cms_autoload($className) {
    global $cms;
    $file = __DIR__."/classes/$className.inc";
    if(is_file($file))
      require_once($file);
  }

  /****** ANALYSE THE REQUEST FOR AW_STATS *******/
  if(isset($_GET['req']))
    $request = $_GET['req'];
  else
    $request = '';
  if(!$request && isset($_SERVER['QUERY_STRING']))
    $request = $_SERVER['QUERY_STRING'];
  $request = preg_replace('/t-f/','/content/',$request);
  // Handle AwStatsMiscTracker requests here.
  if($request == '/awstats_empty.php') {
    $file = __DIR__."/thirdparty/awstats/empty.php";
    if(is_file($file)) {
      require_once($file);
      exit;
    }
  }

  /****** ANTI HACK MEASUREMENTS: DISALLOW CERTAIN REQUEST METHODS *******/
  if(isset($_SERVER['REQUEST_METHOD'])) {
    if(   $_SERVER['REQUEST_METHOD'] == 'CONNECT'
       || $_SERVER['REQUEST_METHOD'] == 'TRACE'
       || $_SERVER['REQUEST_METHOD'] == 'TRACK'
       || $_SERVER['REQUEST_METHOD'] == 'OPTIONS'
       || $_SERVER['REQUEST_METHOD'] == 'PUT'
       || $_SERVER['REQUEST_METHOD'] == 'DELETE'
    ) {
      $logStr = "CMS Method not allowed: method=$_SERVER[REQUEST_METHOD] site=$_SERVER[HTTP_HOST] request=$_SERVER[REQUEST_URI] from=$_SERVER[REMOTE_HOST] ip=$_SERVER[REMOTE_ADDR]";
      `logger "$logStr"`;
      header($_SERVER["SERVER_PROTOCOL"]." 405 Method Not Allowed");
      echo "Method Not Allowed\n";
      exit;
    }
  }

  /****** ANTI HACK MEASUREMENTS: EXAMINE IF IT WAS A KNOWN ATTACK *******/
  // Examine if it was an attack
  $attacks = [
    'administrator'=>'administrator/',
    'api/v2_soap'=>'/api/v2_soap/',
    'assetmanager.asp'=>'/assetmanager.asp',
    'assetmanager.php'=>'/assetmanager.php',
    'awstats.pl'=>'awstats\.pl',
    'boards/includes'=>'boards/includes/',
    'cgi'=>'cgi/',
    'cgi-bin'=>'cgi-bin/',
    'common/scripts'=>'common/scripts',
    '-dallow_url_fopen'=>'-dallow_url_fopen',
    'etc/passwd'=>'/etc/passwd',
    'fckeditor'=>'/fckeditor/',
    'filemanager'=>'/filemanager/',
    'forum/includes'=>'forum/includes/',
    'forums/includes'=>'forums/includes/',
    'log4j 1'=>'/jndi:',
    'log4j 2'=>'/jndi%3a',
    'log4j 3'=>'/jndi%3A',
    'phpThumb'=>'phpThumb/phpThumb',
    'phpmyadmin'=>'phpmyadmin/',
    'public/plugins'=>'public/plugins',
    'this.postImages'=>'this.postimages',
    'uploadTester'=>'uploadTester.asp',
    'vbforum/includes'=>'vbforum/includes/',
    'vb/includes'=>'vb/includes/',
    'vBulletin/includes'=>'vBulletin/includes/',
    'wp-admin'=>'wp-admin',
    'wp-includes'=>'wp-includes',
    'wp-login'=>'wp-login',
  ];
  if(isset($_SERVER['REQUEST_URI'])) {
    foreach($attacks as $name=>$regexp) {
      if(
        preg_match('#'.$regexp.'#i',$_SERVER['REQUEST_URI'])
        || (!empty($_SERVER['HTTP_REFERER']) && preg_match('#'.$regexp.'#i',$_SERVER['HTTP_REFERER']))
      ) {
        $logStr = "CMS Attack: $name: site=$_SERVER[HTTP_HOST] request=$_SERVER[REQUEST_URI] method=$_SERVER[REQUEST_METHOD] from=$_SERVER[REMOTE_HOST] ip=$_SERVER[REMOTE_ADDR]";
        `logger "$logStr"`;
        header($_SERVER["SERVER_PROTOCOL"]." 404 Not Found");
        echo "Forbidden";
        exit;
      }
    }
  }

  /****** HANDLE CACHE REQUESTS RIGHT HERE (unless there is a get parameter) *******/
  $ext = preg_replace('/.*\.(\w*)$/','\1', $request);
  switch($ext) {
    case 'png':
    case 'jpg':
    case 'jpeg':
    case 'gif':
      $cache = new CacheImage();
      if($cache->request($request))
        return;
      break;
    case 'css':
    case 'scss':
      if(!preg_match('/^\/_cache/',$request))
        $request = '/_cache/'.$request;
      $request = preg_replace('#/+#','/',$request);
      $cache = new CacheCss();
      if($cache->request($request))
        return;
      break;
    case 'js':
      if(!preg_match('/^\/_cache/',$request))
        $request = '/_cache'.$request;
      $request = preg_replace('#/+#','/',$request);
      $cache = new CacheJavascript();
      if($cache->request($request))
        return;
      break;
    // Support for direct loading of fonts
    case 'eot':
    case 'woff':
    case 'woff2':
    case 'ttf':
    case 'otf':
    case 'svg':
      if(preg_match('/^\/_cache/',$request))
        preg_replace('/_cache/', '', $request);
      $request = preg_replace('#/+#','/',$request);
      $cache = new CacheFont();
      if($cache->request($request))
        return;
      break;
    // Note: soundfiles and json needs no processing either 
    case 'json':
    case 'mp3':
    case 'ogg':
      if(preg_match('/^\/_cache/',$request))
        preg_replace('/_cache/', '', $request);
      $request = preg_replace('#/+#','/',$request);
      $cache = new CachePlain();
      if($cache->request($request))
        return;
      break;
  }

  /****** HANDLE SOME OTHER TYPES *******/

  // TODO: better mechanism for favicon and mobile-icons
  // If a favicon is requested at this stage, there is none in the document root.
  // In that case send the default favicon
  if(isset($_SERVER['REQUEST_URI']) && preg_match('#/favicon\.ico$#',$_SERVER['REQUEST_URI'])) {
    $file = $_SERVER['DOCUMENT_ROOT'].'/favicon.ico';
    if(!is_file($file))
      $file = $_SERVER['DOCUMENT_ROOT'].'/'.$cms_dir.'images/icons/default_favicon.ico';
    if(is_file($file)) {
      header("Content-Type: image/vnd.microsoft.icon");
      header("Accept-Ranges: bytes");
      $size = filesize($file);
      header("Content-Length: $size");
      readfile($file);
      exit;
    }
  }

  // handling for multimedia
  if(preg_match('/^\/multimedia/',$request)) {
    $file = $_SERVER['DOCUMENT_ROOT']."/multimedia/".basename($request);
    if(is_file($file)) {
      $mime = MimeType::getType($file);
      if(!$mime) $mime = "application/octet-stream";
      header("Content-Type: $mime");
      header("Accept-Ranges: bytes");
      $size = filesize($file);
      header("Content-Length: $size");
      header('Content-Transfer-Encoding: binary');
      header('Cache-Control: must-revalidate');
      readfile($file);
      exit;
    }
  }
  // TODO: handling for securemedia
  // TODO: handling for robots.txt
  // TODO: handling for sitemap.xml

  // Handling of security.txt
  if(preg_match('/^\/.well-known\/security.txt/',$request)) {
    gen_security_txt();
  }

  /****** NONE OF THE ABOVE: LET THE CMS HANDLE THE REQUEST *******/

  // EdM 2025-03-25: Use __DIR__ (place of entry.php) for the includes below
  include_once(__DIR__."/toolbox/common/common_tbx.inc");
  include_once(__DIR__."/toolbox/common/check_htuser.inc");

  $cms = new Cms();
  $cms->setup();

  /****** HANDLE JAVASCRIPT ERROR CALLBACKS *******/
  if($request == '/cmsjavascripterror') {
    $cms->warning("!!! JAVASCRIPT ERROR !!!: ".$cms->query->get['msg']);
  }

  /****** HANDLE OAUTH REQUESTS *******/
  if($request == '/oauth2callback') {
    if($cms->query->get['state']) {
      $cms->db->read_array($oauth2, "SELECT * FROM volatile.oauth2 WHERE state=?",array($cms->query->get['state']));
    }
    if($cms->query->get['oauth_token']) {
      $cms->db->read_array($oauth2, "SELECT * FROM volatile.oauth2 WHERE account_json_token LIKE CONCAT('%',?,'%')",array($cms->query->get['oauth_token']));
    }
    if($oauth2['state']) {
      if($oauth2['parms'])
        $oauth2['parms'] = json_decode($oauth2['parms']);
      $client = new OAuthClient();
      $client->server = $oauth2['parms']->server;
      $client->redirect_uri = $oauth2['parms']->redirect_uri;
      $client->scope = $oauth2['parms']->scope;
      $client->offline = true;
      $client->client_id = $oauth2['account_key'];
      $client->client_secret = $oauth2['account_secret'];
      if(($success = $client->Initialize())) {
        if(($success = $client->Process())) {
          if(strlen($client->authorization_error)) {
            $client->error = $client->authorization_error;
            $success = false; 
          }
        }
        $success = $client->Finalize($success);
      }
      if($oauth2['redirected_url']) {
        Header('HTTP/1.0 302 OAuth Redirection');
        Header('Location: '.$oauth2['redirected_url']);
        exit;
      }
    }
  }

  /****** HANDLE WEB REQUESTS *******/
  if(php_sapi_name() !== "cli") {
    if($cms->debug) {
      $cms->log("Headers received with request:\n");
      $headers = getallheaders();
      foreach($headers as $header => $value)
        $cms->log("$header: $value\n");
      if($cms->debug > 1) {
        $cms->log("cms object:\n");
        $cms->log(print_r($cms,1));
      }
      else {
        $cms->log("request=".$cms->query->req."<br />\n");
        $cms->log("get parameters:\n");
        $cms->log(print_r($cms->query->get,1));
      }
    }
    if($cms->query->popup) {
      // This is an popup (ajax-html) request, only return the contents of the page (not the surrounding site)
      $content = new Content();
      Password::checkLoginFields(); // Let the plug-in do this
      $msgFiles = $content->addMessagesFiles();
      if (is_array($msgFiles)) {
        $msgFiles = array_unique($msgFiles);
        foreach($msgFiles as $msgFile)
          $cms->msgs->read_msg_file($msgFile);
      }
      $content->setParameters();
      $msgFiles = $content->addMessagesFiles();
      if (is_array($msgFiles)) {
        $msgFiles = array_unique($msgFiles);
        foreach($msgFiles as $msgFile)
          $cms->msgs->read_msg_file($msgFile);
      }
      $content->procGet($cms->query->get);
      $content->procPost($cms->query->post);
      $title = $cms->site_name;
      $cssFiles = $content->addCssFiles();
      foreach($cssFiles as $file)
        echo "<link rel=\"stylesheet\" type=\"text/css\" href=\"$file\">";
      $css = $content->addToCss('');
      if($css) 
        echo '<style type="text/css">'.$css.'</style>';
      echo $content->addToBody();
      $jsFiles =  $content->addJavascriptFiles();
      foreach($jsFiles as $file)
        echo "<script type=\"text/javascript\" src=\"$file\"></script>";
      $js =  $content->addToJavascript($js);
      if($js)
        echo "<script type=\"text/javascript\"><!--\n".$js."\n//--></script>";
    }
    else {
      $custom_style_path = str_replace('content','site_style', $cms->customcontentpath);
      if(is_file($custom_style_path.$cms->query->proc.".php"))
        include($custom_style_path.$cms->query->proc.".php");
      else if(is_file($cms->stylepath.$cms->query->proc.".php"))
        include($cms->stylepath.$cms->query->proc.".php");
      else if(is_file($cms->cmspath."processors/".$cms->query->proc.".php"))
        include($cms->cmspath."processors/".$cms->query->proc.".php");
      else {
        $cms->header_status = 404;
        header($_SERVER["SERVER_PROTOCOL"]." 404 Not Found");
        echo "<span style=\"color:red;\">Het bestand werd niet gevonden!!</span>\n";
        // Unresolved request, generate 404 and log to /var/log/messages so fail2ban can detect possible brute-force attack...
        $logStr =  "CMS Unresolved request (entry): site=$_SERVER[HTTP_HOST] request=$_SERVER[REQUEST_URI]";
        $logStr .= " from=$_SERVER[REMOTE_HOST] ip=$_SERVER[REMOTE_ADDR]";
        $logStr .= " sel=".$cms->query->sel;
        `logger "$logStr"`;
        echo "<!-- 404 Not Found: ".$cms->query->sel." -->\n";
        exit;
      }
    }
  }

  function gen_security_txt() {
    header('Content-Type: text/plain; charset=utf-8');
    $file = $_SERVER['DOCUMENT_ROOT'].'/security.txt';
    if(is_file($file))
      $security = file_get_contents($file);
    else{  // Defaut content
      $security .= 'Contact: https://creagraphy.nl/security-breach'."\n";
      $security .= 'Expires: '.date('Y-m-d\TH:i:s\Z', strtotime("+3 months"))."\n";
      $security .= 'Canonical: https://'.$_SERVER['SERVER_NAME'].'/.well-known/security.txt'."\n";
      $security .= "Preferred-Languages: nl, en\n\n";
    }
    echo $security;
    exit;
  }

?>
