<?php
/**
 * @copyright (c) Kufer Software GmbH, Loisachstrasse 4, D-84453 Mühldorf
 */


class UploadOperations
{
  
  public static function getAttachments($pFormname4Anhang)
  {
    $zentralsettings = ToolSettingsAPI::getToolSettings(0);

    if (SessionOperations::isKuferTools()) {
      $uploadMaxFileSize = $zentralsettings->uploadmaxsize;
      $uploadMaxFileNumber = $zentralsettings->uploadmaxcount;
      $fileUploadPath = $zentralsettings->uploadpath;
    } else {
      $uploadMaxFileSize = $zentralsettings->fileUploadMaxFileSize;
      $uploadMaxFileNumber = $zentralsettings->fileUploadMaxFileNumber;
      $fileUploadPath = $zentralsettings->fileUploadPath;
    }

    return self::doUpload(
      $pFormname4Anhang,
      $fileUploadPath,
      $uploadMaxFileNumber,
      $uploadMaxFileSize
    );
  }

  
  public static function doUpload(
    $pFormname4Anhang,
    $pFileUploadPath,
    $pMaxUploadCounter,
    $pFileUploadMaxFileSize,
    $pUploadFileStrategy = null,
    $pFileNameCounter = 1,
    $pOverwriteExistingFile = false,
    $pNewFileName = ''
  ) {
    return self::doUploadFiles(
      $_FILES,
      $pFormname4Anhang,
      $pFileUploadPath,
      $pMaxUploadCounter,
      $pFileUploadMaxFileSize,
      $pUploadFileStrategy,
      $pFileNameCounter,
      $pOverwriteExistingFile,
      $pNewFileName
    );
  }

  
  public static function doUploadFiles(
    $pFiles,
    $pFormname4Anhang,
    $pFileUploadPath,
    $pMaxUploadCounter,
    $pFileUploadMaxFileSize,
    $pUploadFileStrategy = null,
    $pFileNameCounter = 1,
    $pOverwriteExistingFile = false,
    $pNewFileName = ''
  ) {
    
    $fileCounter = 0;
    $errorOutput = '';

    $blackOrWhiteListAry = self::getBlackOrWhiteListAry();

    
    $uploadfileAry = array();
    
    
    $doUpload = true;

    
    
    $illegalFileNames = self::getIllegalUploadFilenames($pFiles, $blackOrWhiteListAry, $pFormname4Anhang);
    $illegalFileNameCnt = count($illegalFileNames);

    if ($illegalFileNameCnt > 0) {
      $uploadfileAry = array_merge(self::getIllegalFileAttachments($pFiles, $illegalFileNames), $uploadfileAry);
      $doUpload = false;
    }

    $maxFileSize = ConstantOperations::getMaxFileSize4Upload($pFileUploadMaxFileSize);

    
    for ($i = 1; ($i <= $pMaxUploadCounter); $i++) {
      
      if ($pMaxUploadCounter == 1 && $pFileNameCounter === '') {
        $filename = $pFormname4Anhang;
      } else {
        $filename = $pFormname4Anhang . $i; 
      }
      if (isset($pFiles[$filename]) && $pFiles[$filename]['size'] > 0) {

        
        if ($pMaxUploadCounter == 1 && $pFileNameCounter === '' && $pNewFileName !== '') {
          $pFiles[$filename]['name'] = $pNewFileName;
        }

        
        if (($fileCounter >= $pMaxUploadCounter)) {
          Logger::logg('Dateiupload: Datei ' . $pFiles[$filename]['name'] . ' würde das Limit der maximal hochladbaren Dateien von '
            . $pMaxUploadCounter . ' überschreiten', 20);
          $errorOutput = self::getAttachmentError('Fehler beim Hochladen der Datei ' . $pFiles[$filename]['name'] . ': insgesamt können maximal '
            . $pMaxUploadCounter . ' Dateien hochgeladen werden.');
          
          $uploadfileAry[] = new Attachment(
            $pFiles[$filename]['name'],
            $pFiles[$filename]['tmp_name'],
            $pFiles[$filename]['type'],
            $pFiles[$filename]['size'],
            UPLOAD_ERR_NO_FILE,
            $errorOutput
          );

          continue;
        }

        
        if (!StringOperations::isDotAtBeginOfString($pFiles[$filename]['name']) && CleanOperations::isFileNameWithAllowedChars($pFiles[$filename]['name'])
                && (self::isAnyExtAllowed4Attachment($pFormname4Anhang) || !StringOperations::isExcludedFileExt($blackOrWhiteListAry, $pFiles[$filename]['name']))) {
          
          if ($pFiles[$filename]['size'] > $maxFileSize) {
            Logger::logg('Dateiupload: Datei ' . $pFiles[$filename]['name'] . ' ist zu groß für den Upload (' . \Kufer\Web\Classes\Addfunctions\MemorySizeOperations::makeHumanReadable((int)$pFiles[$filename]['size']) . ' , nur '
              . \Kufer\Web\Classes\Addfunctions\MemorySizeOperations::makeHumanReadable((int)$maxFileSize) . ' erlaubt)', 30);
            $errorOutput = self::getAttachmentError('Fehler beim Hochladen der Datei ' . $pFiles[$filename]['name'] . ': die Datei ist zu groß - maximal '
                           . \Kufer\Web\Classes\Addfunctions\MemorySizeOperations::makeHumanReadable((int)$maxFileSize) . ' erlaubt.');
            
            $uploadfileAry[] = new Attachment(
              $pFiles[$filename]['name'],
              $pFiles[$filename]['tmp_name'],
              $pFiles[$filename]['type'],
              $pFiles[$filename]['size'],
              UPLOAD_ERR_FORM_SIZE,
              $errorOutput
            );
            $doUpload = false;
          } else {
            $localFileDir = $pFileUploadPath;
            if (UPLOAD_ERR_OK !== $pFiles[$filename]['error']) {
              
              Logger::logg('Dateiupload: Fehler beim Hochladen der Datei: ' . $pFiles[$filename]['error'], 100);
              $errorOutput = self::getAttachmentError('Interner Fehler beim Hochladen der Datei ' . $pFiles[$filename]['name'] . '.');
              
              $uploadfileAry[] = new Attachment(
                $pFiles[$filename]['name'],
                $pFiles[$filename]['tmp_name'],
                $pFiles[$filename]['type'],
                $pFiles[$filename]['size'],
                UPLOAD_ERR_NO_FILE,
                $errorOutput
              );
              $doUpload = false;
            }
          } 


          if ($doUpload) {
            
            
            
            if ($pUploadFileStrategy == null) {
              $pUploadFileStrategy = new StandardUploadFileStrategy();
            }

            $uploadfileAry[] = $pUploadFileStrategy->execute($pFiles, $localFileDir, $filename, $pFileNameCounter, $pOverwriteExistingFile);
            
            $fileCounter++;
          } 
          else {
            if ($illegalFileNameCnt > 0) {
              if (!isset($illegalFileNames[$filename])) {
                $errorOutput = self::getAttachmentError('Fehler beim Hochladen anderer Dateien. Datei ' . $pFiles[$filename]['name'] . ' wurde daher nicht hochgeladen.');
                $uploadfileAry[] = new Attachment(
                  $pFiles[$filename]['name'],
                  $pFiles[$filename]['tmp_name'],
                  $pFiles[$filename]['type'],
                  $pFiles[$filename]['size'],
                  UPLOAD_ERR_PARTIAL,
                  $errorOutput
                );
              }
            }
          } 
        } 
      } 
    } 
    
    return $uploadfileAry;
  }

  

  
  public static function getAttachmentError($pErrorMessage)
  {
    $errorMessage = '';
    if (!empty($pErrorMessage)) {
      $errorMessage = '<div class="error">' . CleanOperations::cleanStringForHtml($pErrorMessage) . '</div>';
    }

    return $errorMessage;
  }

  
  public static function getIllegalUploadFilenames($pFiles, $pBlackOrWhiteListAry, $pFormname4Anhang)
  {
    $isAnyExtAllowed4Attach = self::isAnyExtAllowed4Attachment($pFormname4Anhang);
    $result = array();

    foreach ($pFiles as $filename => $fileObj) {

      
      if ($fileObj['error']) {
        continue;
      }

      
      if (StringOperations::isDotAtBeginOfString($fileObj['name'])) {
        $result[$filename] = $filename;
      } elseif (!CleanOperations::isFileNameWithAllowedChars($fileObj['name'])) {
        $result[$filename] = $filename;
      } elseif (!$isAnyExtAllowed4Attach && ($exclExt = StringOperations::isExcludedFileExt($pBlackOrWhiteListAry, $fileObj['name'])) !== '') {
        $result[$filename] = $exclExt;
      }
    } 

    return $result;
  }

  
  public static function isAnyExtAllowed4Attachment($pFormname4Anhang)
  {
    $toolSettings = ToolSettingsAPI::getToolSettings(0);

    return $pFormname4Anhang === 'anhang' && !$toolSettings->useAllowedExt4Attach;
  }

  
  public static function delUploadedFiles($pUploadfileAry)
  {
    foreach ($pUploadfileAry as $attachment) {

    
      if (file_exists($attachment->name)) {
        unlink($attachment->name);
      }
    }
  }

  

  
  public static function getIllegalFileAttachments($pFiles, $pIllegalFileNames)
  {
    $uploadfileAry = array();
    foreach ($pIllegalFileNames as $filename => $fileExt) {
      $logPart = '';
      if (StringOperations::isDotAtBeginOfString($pFiles[$filename]['name'])) {
        $statMsgPart = 'Die Datei hat keinen Namen. Sie darf deshalb nicht hochgeladen werden.';
      } elseif (!CleanOperations::isFileNameWithAllowedChars($pFiles[$filename]['name'])) {
        $statMsgPart = 'Der Dateiname enthält Umlaute, Leerzeichen oder verbotene Sonderzeichen.';
      } elseif ($fileExt != '' && $pFiles[$filename]['name'] === $fileExt) {
        $statMsgPart = 'Die Datei hat keine Endung und das Ende des Dateinamens ist nicht freigegeben. Sie darf deshalb nicht hochgeladen werden.';
        $logPart = 'Dateiupload: Aus Sicherheitsgründen ist es nicht erlaubt, Dateien ohne Endung hochzuladen, dessen Dateinamen nicht mit einem '
                    . 'zulässigen String enden.';
      } else {
        $statMsgPart = 'Die Datei hat die Endung ' . $fileExt . ' und darf deshalb nicht hochgeladen werden.';
        $logPart = 'Dateiupload: Aus Sicherheitsgründen ist es nicht erlaubt, Dateien mit der Endung ' . $fileExt . ' hochzuladen';
      }

      $errorOutput = self::getAttachmentError('Fehler beim Hochladen der Datei ' . $pFiles[$filename]['name'] . ': ' . $statMsgPart);
      Logger::logg($logPart . ' Daher ist für Datei ' . $pFiles[$filename]['name'] . ' ein Upload nicht möglich', 40);

      $uploadfileAry[] = new Attachment(
        $pFiles[$filename]['name'],
        $pFiles[$filename]['tmp_name'],
        $pFiles[$filename]['type'],
        $pFiles[$filename]['size'],
        UPLOAD_ERR_EXTENSION,
        $errorOutput
      );
    }

    return $uploadfileAry;
  }

  public static function getBlackOrWhiteListAry()
  {
    $tool0Settings = ToolSettingsAPI::getToolSettings(0);

    if ($tool0Settings->dokuUploadAllowByExclude) {
      
      $listAry = explode(',', $tool0Settings->uploadBlacklist4Ext); 
      $type = 'blacklist';
    } else {
      
      $listAry = explode(',', $tool0Settings->uploadWhitelist4Ext); 
      $type = 'whitelist';
    }

    return array('list' => $listAry, 'type' => $type);
  }
}