<?php
/*
  www.oscGold.com (C) Kamelia-Net Jacek Krysiak
  modul oscGold wer 4.0
*/

function AddToExcludeList($curList, $newItem)  //check to see if the new path is already in the list
{
  if (empty($curList))                  //add a comma separator where needed
   $comma = '';
  else if (strpos($curList, ",") === FALSE)
   $comma = ',';
  else
   $comma = ",";

  $found = 0;
  $parts = explode(",", $curList);
  for ($i = 0; $i < count($parts); ++$i)
  {
     $item = substr($parts[$i], 1, strlen($parts[$i]) - 2);
     if (strstr($item, $newItem) != FALSE)
     {
        $found = 1;
        break;
     }
  }

  return (($found) ? $curList : stripslashes(sprintf("%s%s\"%s\"",$curList, $comma, $newItem)));
}

function CheckExcludeList($str)
{
  if (empty($str) || $str[0] != '"')     //list does not begin with a quote
    return "BLAD: Lista wykluczen nie moze rozpoczynac sie od cudzyslowu.";

  $parts = explode(",", $str);
  for ($i = 0; $i < count($parts); ++$i)
  {
    $parts[$i] = trim($parts[$i]);
    if ($parts[$i][0] != '"' || $parts[$i][strlen($parts[$i])-1] != '"')
      return (sprintf("BLAD: %s nie zostal ograniczony cudzyslowami.",$parts[$i]));   //each item is not surrounded by quotes
  }

  $cleanstring = ereg_replace("[ \t\r\n]+","",trim($str));

  return $cleanstring;                   //remove spaces, tabs and newlines
}

function CheckLogSize()  //create a new log file if current one is too large
{
  global $logfile, $logfile_size;

  if ($logfile && (int)$logfile_size > 0 && filesize('tmp/sitemonitor_log.txt') >= $logfile_size)
  {
    if (copy('tmp/sitemonitor_log.txt', 'tmp/sitemonitor_log_' .  date("d_m_Y") . '.txt'))
    {
      if (($fp = fopen("tmp/sitemonitor_log.txt", "w")))
        fclose($fp);
    }
  }
}

function CreateReferenceFile($dir,$level,$last,&$files)
{
  $dp=opendir($dir);

  while (false!=($file=readdir($dp)) && $level == $last)
  {
     if ($file!="." && $file!="..")
     {
        $path = $dir."/".$file;
        if (is_dir($path))
        {
          if (ExcludeDirectory($path))
            continue;

          CreateReferenceFile($path,$level+1,$last+1,$files); // uses recursion
        }
        else
        {
          if (strpos($file, "sitemonitor_reference.php") !== FALSE || strpos($file, "error_log") !== FALSE )
            continue;

          $locn = "$dir/$file";
          $r = @stat($locn);
          $str = sprintf("%s,%d,%d,%d", $locn, $r[7], $r[9],substr(sprintf('%o', @fileperms($locn)), -3));
          $files[] = $str;  // reads the file into an array
        }
     }
  }
}

function DisplayMessage($verbose, $msg)
{
  $str = $msg;
  if ($verbose) echo $str . '<br>';
  return ($str . "\n");
}

function ExcludeDirectory($dir)
{
  global $excludeList;
  $path = GetDirectoryName($dir);
  return (in_array($path, $excludeList));
}

function GetConfigureSetting($str, $beginDelimiter, $endDelimiter)
{
  if (($posStart = strpos($str, $beginDelimiter)) !== FALSE)
  {
    if (($posStop = strpos($str, $endDelimiter, $posStart + 1)) !== FALSE)
     return (substr($str, $posStart + 1, $posStop - $posStart - 1));
  }
  return '';
}

function GetDirectoryName($path)  //return the partial directory
{
  global $start_dir;
  return (substr($path, strlen($start_dir) + 1));
}

function GetFileName($full_path)
{
  global $start_dir;
  return substr($full_path, strlen($start_dir) + 1);
}

function GetList($dir, $level, $last, $dir_list)
{
  $dp=opendir($dir);

  while (false!=($file=readdir($dp)) && $level == $last)
  {
     if ($file!="." && $file!="..")
     {
        if (is_dir($dir.$file))
        {
            $dir_list[] = $dir.$file;
            $dir_list = GetList($dir.$file."/",$level+1,$last+1, $dir_list);
        }
     }
  }

  closedir($dp);
  return $dir_list;
}

function GetSize($path)
{
  if(!is_dir($path))return @filesize($path);
  $dir = opendir($path);
  while($file = readdir($dir))
  {
    if(is_file($path."/".$file))$size+=filesize($path."/".$file);
    if(is_dir($path."/".$file) && $file!="." && $file !="..")$size +=get_size($path."/".$file);
  }
  return $size;
}

function GetPart($part, $path)
{
  $parts = explode(",", $path);
  return trim($parts[$part]);
}

function GetReferenceFiles($referenceFile)
{
   $refFiles = "";
   if (!( $refFiles = file($referenceFile)))
   {
     echo 'Nie mozna odczytac pliku referencyjnego';
     exit;
   }
   return $refFiles;
}

function WriteFile($filename, $files)
{
  $fpOut = fopen($filename, "w");

  if (! $fpOut)
  {
     echo 'Nie mozna otworzyc pliku '.$filename;
     exit;
  }

  for ($idx = 0; $idx < count($files); ++$idx)
  {
    $str = $files[$idx]."\n";
    $str = str_replace('./','',$str);
    if (fwrite($fpOut, $str) === FALSE)
    {
       echo "Nie mozna zapisac do pliku ($filename)";
       exit;
    }
  }
  fclose($fpOut);
}

function WriteConfigureFile($filename, $fp)
{
  if (!is_writable($filename))
  {
     if (!chmod($filename, 0666)) {
        echo "Nie mozna zmienic uprawnien do pliku ($filename)";
        exit;
     }
  }
  $fpOut = fopen($filename, "w");

  if (!fpOut)
  {
     echo 'Nie mozna otworzyc pliku '.$filename;
     exit;
  }

  for ($idx = 0; $idx < count($fp); ++$idx)
  {
    if (fwrite($fpOut, $fp[$idx]) === FALSE)
    {
       echo "Nie mozna zapisac do pliku ($filename)";
       exit;
    }
  }
  fclose($fpOut);
}

function WriteLogFile($logEntry, $today)
{
  $fp = fopen("tmp/sitemonitor_log.txt", "a");

  if ($fp)
  {
    fputs($fp, "Zawartosc monitora " . $today. "\n");

    if (count($logEntry) == 0)
      fputs($fp, "Nie znaleziono roznic\n");
    else
    {
      foreach(array_keys($logEntry) as $groupKey)
      {
        fputs($fp, $groupKey . "\n");

        foreach($logEntry[$groupKey] as $item)
          fputs($fp, "\t" .$item . "\n");
      }
    }
    fputs($fp, "\n\n");
    fclose($fp);
  }
}

function runSitemonitor($verbose)
{
  global $start_dir, $always_email, $logfile, $excludeList, $quarantine, $to, $from;

  define('NAME', 0);
  define('SIZE', 1);
  define('TIME', 2);
  define('PERM', 3);

  $msg = '';
  $level=1; // level is the first level started at
  $last=1; //this is set the same as level
  $files = array();
  $logEntry = array();

  CheckLogSize();
  clearstatcache();

  /************** READ IN THE FILES ****************/
  CreateReferenceFile($start_dir, $level, $last, $files);

  /************** SAVE THE FILES OR, IF PRESENT, READ THEM IN ****************/
  $referenceFile = "sitemonitor_reference.php";
  if (! file_exists($referenceFile))
  {
    if (empty($files))
    {
      echo 'Nie mozna utworzyc pliku referencyjnego.';
      return -1;
    }

    WriteFile($referenceFile, $files);
    if ($verbose) echo 'Pierwsze uruchomienie monitora. Plik referencyjny zostal utworzony.';
    return -2;
  }
  else
  {
    $refFiles = GetReferenceFiles($referenceFile);   //read in the saved file
    $size = count($refFiles);

    for ($i = 0; $i < $size; ++$i)
    {
      $refFiles[$i] = rtrim($refFiles[$i]);
      $pos = strpos($refFiles[$i], ",");
      $refFiles[$i] = substr($refFiles[$i], 0, $pos);
    }
  }

  /************** COVERT NEW FILES TO NORMAL FILENAME ****************/
  $size = count($files);
  for ($i = 0; $i < $size; ++$i)
  {
    $files[$i] = str_replace("./", "", $files[$i]);
    $pos = strpos($files[$i], ",");
    $files[$i] = substr($files[$i], 0, $pos);
  }

  /************** SEE IF THERE ARE ANY NEW FILES ****************/
  $diff_added = array_diff($files, $refFiles);
  $msg = "NOWE PLIKI:\n";
  $ttlErrors = 0;

  if (count($diff_added) > 0)
  {
     foreach($diff_added as $key => $value)  //can't use for loop due to keys staying constant - key 0 may not be present
     {
       $msg .= DisplayMessage($verbose, ('Znaleziono nowy plik ' . GetFileName($value)));
       $logEntry['New File Added'][] = $value;
       $ttlErrors++;

       if ($quarantine)                     //new found file is to be moved to a safe directory
       {
         $file = GetFileName($value);
         $newfile = "quarantine/$file";     //get new file location and name

         if (file_exists($newfile))         //rename won't overwrite so create a new name
         {
           $path_parts = pathinfo($file);
           if (($pos = strpos($file, $path_parts['extension'])) !== FALSE) //get the extension
             $newfile = sprintf("quarantine/%s_%s.%s  ",substr($file, 0, strlen($file) - $pos), date("d_m_Y"),$path_parts['extension'] );
         }

         if (rename($value, $newfile))      //move the file
         {
           $msg .= DisplayMessage($verbose, ('Quarantined new file: ' . GetFileName($value)));
           $logEntry['New File Quarantined'][] = $value;
         }
       }
     }
  }
  else
     $msg .= DisplayMessage($verbose, 'Brak nowych plikow...');

  /************** SEE IF THERE ARE ANY DELETED FILES ****************/
  $diff_deleted = array_diff($refFiles, $files);
  $msg .= "\nUSUNIETE PLIKI:\n";

  if (count($diff_deleted) > 0)
  {
     foreach($diff_deleted as $key => $value)  //can't use for loop due to keys staying constant - key 0 may not be present
     {
        $msg .= DisplayMessage($verbose, ('Usuniete pliki ' . GetFileName($value)));
        $logEntry['File Deleted'][] = $value;
        $ttlErrors++;
     }
  }
  else
    $msg .= DisplayMessage($verbose, 'Brak usunietych plikow...');

  /************** SEE IF THE FILE SIZES ARE DIFFERENT ****************/
  $error = 0;
  $msg .= "\nROZNICE WIELKOSCI PLIKOW:\n";

  if (! $diff_deleted)
  {
    $size = count($files);
    $refFiles = GetReferenceFiles($referenceFile);  //reload for all checks below

    if ($size == count($refFiles))
    {
      for ($i = 0; $i < $size; ++$i)
      {
         $newSize = GetSize($files[$i]);
         $oldSize = GetPart(SIZE, $refFiles[$i]);
         if ($newSize != $oldSize)
         {
            $msg .= DisplayMessage($verbose, ('Znalezione roznice wielkosci plikow: Nowy-> '. GetFileName($files[$i]) . ' '. $newSize . ' Oryginalny-> ' . $oldSize));
            $logEntry['Size Changed'][] = $files[$i];
            $error++;
            $ttlErrors++;
         }
      }
    }
    else if ($size > count($refFiles))  //files were added
    {
       $sizeA2 = count($refFiles);

       for ($i = 0; $i < $size; ++$i)
       {
         if (in_array($files[$i], $diff_added))        //ignore the new file
            continue;

         for ($t = 0; $t < $sizeA2; ++$t)
         {
            if ($files[$i] === GetPart(NAME, $refFiles[$t]))
            {
               $newSize = GetSize($files[$i]);
               $oldSize = GetPart(SIZE, $refFiles[$t]);
               if ($newSize != $oldSize)
               {
                 $msg .= DisplayMessage($verbose, ('Znalezione roznice: Nowy-> '. GetFileName($files[$i]) . ' '.$newSize. ' Oryginalny-> ' .$oldSize));
                 $logEntry['Size Changed'][] = $files[$i];
                 $error++;
                 $ttlErrors++;
                 break;
               }
            }
         }
       }
    }
    if (! $error)
      $msg .= DisplayMessage($verbose, 'Nie znaleziono roznic wielkosci plikow...');
  }
  else
    $msg .= DisplayMessage($verbose, 'Wielkosci nie zostaly porownane poniewaz pliki sa usuniete');

  /************** SEE IF THE TIMESTAMPS ARE DIFFERENT ****************/

  $msg .= "\nRZONICE CZASU MODYFIKACJI PLIKOW:\n";
  if (! $diff_deleted)
  {
    $error = 0;
    $size = count($files);

    if ($size == count($refFiles)) //increase by one to account for sitemonitor_reference.php
    {
       for ($i = 0; $i < $size; ++$i)
       {
          $r = @stat($files[$i]);
          if ($r[9] != GetPart(TIME, $refFiles[$i]))
          {
            $msg .= DisplayMessage($verbose, ('Roznice czasu '. GetFileName($files[$i]). ' Ostatnia modyfikacja  ' . gmstrftime ("%A, %d %b %Y %T %Z", $r[9])));
            $logEntry['Time Changed'][] = $files[$i];
            $error++;
            $ttlErrors++;
          }
        }
     }
     else if ($size > count($refFiles))
     {
       $sizeA2 = count($refFiles);

       for ($i = 0; $i < $size; ++$i)
       {
         if (in_array($files[$i], $diff_added))        //ignore the new file
            continue;

         for ($t = 0; $t < $sizeA2; ++$t)
         {
            if ($files[$i] === GetPart(NAME, $refFiles[$t]))
            {
               $r = @stat($files[$i]);
               if ($r[9] != GetPart(TIME, $refFiles[$t]))
               {
                 $msg .= DisplayMessage($verbose, ('Roznice czasu '. GetFileName($files[$i]). ' Ostatnia modyfikacja  ' . gmstrftime ("%A, %d %b %Y %T %Z", $r[9])));
                 $logEntry['Time Changed'][] = $files[$i];
                 $error++;
                 $ttlErrors++;
                 break;
               }
            }
         }
       }
     }
     if (! $error)
       $msg .= DisplayMessage($verbose, 'Nie znaleziono roznic daty modyfikacji...');
   }
   else
     $msg .= DisplayMessage($verbose, 'Roznice czasu nie zostaly porownane poniewaz pliki sa usuniete');


  /************** SEE IF THE PERMISSIONS ARE DIFFERENT ****************/
  $msg .= "\nROZNICE UPRAWNIEN DO PLIKOW:\n";

  if (! $diff_deleted)
  {
    $error = 0;
    $size = count($files);

    if ($size == count($refFiles))
    {
       for ($i = 0; $i < $size; ++$i)
       {
          $pCurrent = substr(sprintf('%o', @fileperms($files[$i])), -3);
          $pLast =  GetPart(PERM, $refFiles[$i]);

          if ($pCurrent != $pLast)
          {
            $msg .= DisplayMessage($verbose, ('Roznice uprawnien '. GetFileName($files[$i]). ' Aktualnie ustawione "' . $pCurrent . '" poprzednie "' . $pLast .'"'));
            $logEntry['Permissions Change'][] = $files[$i];
            $error++;
            $ttlErrors++;
          }
        }
     }
     else if ($size > count($refFiles))
     {
       $sizeA2 = count($refFiles);

       for ($i = 0; $i < $size; ++$i)
       {
         if (in_array($files[$i], $diff_added))        //ignore the new file
            continue;

         for ($t = 0; $t < $sizeA2; ++$t)
         {
            if ($files[$i] === GetPart(NAME, $refFiles[$t]))
            {
               $pCurrent = substr(sprintf('%o', @fileperms($files[$i])), -3);
               $pLast =  GetPart(PERM, $refFiles[$t]);
               if ($pCurrent != $pLast)
               {
                 $msg .= DisplayMessage($verbose, ('Roznice uprawnien '. GetFileName($files[$i]). ' Aktualnie ustawione ' . $pCurrent . ' poprzednie ' . $pLast));
                 $logEntry['Permissions Change'][] = $files[$i];
                 $error++;
                 $ttlErrors++;
                 break;
               }
            }
         }
       }
     }
     if (! $error)
       $msg .= DisplayMessage($verbose, 'Brak roznic uprawnien do plikow...');
   }
   else
     $msg .= DisplayMessage($verbose, 'Roznice uprawnien nie zostaly porownane poniewaz pliki sa usuniete');

   $today = date("F j, Y, g:i a");
   $msg .= DisplayMessage($verbose, '');
   $msg .= DisplayMessage($verbose, '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~');
   $msg .= DisplayMessage($verbose, "Monitor systemu uruchomiony " . $today);
   $msg .= DisplayMessage($verbose, "Ilosc znalezionych roznic " . $ttlErrors);
   $msg .= DisplayMessage($verbose, "Ilosc monitorowanych plikow " . count($refFiles));

   if ($ttlErrors || $always_email)
   {
     mail($to, 'Wyniki dzialania Monitora Systemu', $msg, $from);
     if ($verbose)
      echo 'Mail zostal wyslany do wlasciciela sklepu.' .'<br>';
   }

   if ($logfile)
     WriteLogFile($logEntry, $today);

   return $ttlErrors;
  }
?>