link_filebrowser-1.0.1/src/Controller/LinkFileBrowserController.php

src/Controller/LinkFileBrowserController.php
<?php

namespace Drupal\link_filebrowser\Controller;

use LZCompressor\LZString;
use Drupal\Component\Serialization\Json;
use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\File\FileExists;
use Drupal\Core\File\FileSystemInterface;
use Drupal\Core\Render\RendererInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\StreamWrapper\StreamWrapperManagerInterface;
use Drupal\Core\Url;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\ResponseHeaderBag;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;

/**
 * Returns responses for Link filebrowser routes.
 */
class LinkFileBrowserController extends ControllerBase {

  /**
   * Link file browser Controller constructor.
   *
   * @param \Drupal\Core\Render\RendererInterface $renderer
   *   The render service.
   * @param \Drupal\Core\File\FileSystemInterface $fileSystem
   *   The file system service.
   * @param \Drupal\Core\StreamWrapper\StreamWrapperManagerInterface $streamWrapperManager
   *   The stream wrapper manager.
   * @param \Drupal\Core\Session\AccountInterface $account
   *   The current user.
   */
  public function __construct(protected RendererInterface $renderer, protected FileSystemInterface $fileSystem, protected StreamWrapperManagerInterface $streamWrapperManager, protected AccountInterface $account) {

  }

  /**
   * {@inheritdoc}
   *
   * @param \Symfony\Component\DependencyInjection\ContainerInterface $container
   *   The Drupal service container.
   *
   * @return static
   */
  public static function create(ContainerInterface $container) {
    return new self(
      $container->get('renderer'),
      $container->get('file_system'),
      $container->get('stream_wrapper_manager'),
      $container->get('current_user'),
    );
  }

  /**
   * {@inheritDoc}
   */
  public function listFiles(Request $request, $crypt): JsonResponse {
    $selection_settings = $this->keyValue('filebrowser')->get($crypt);
    if (!empty($selection_settings)) {
      $path = [
        $this->streamWrapperManager->getViaScheme('public')->getDirectoryPath(),
        $selection_settings['folder'],
        $request->request->get('directory'),
      ];
      $directory = $this->cleanPath(implode('/', array_filter($path)), TRUE);
      $all = !empty($selection_settings['all']);
      $maxLevel = $all ? TRUE : 2;
      $response = $this->scan($directory, $maxLevel);
    }
    return new JsonResponse($response ?? []);
  }

  /**
   * {@inheritDoc}
   */
  public function scanFiles(Request $request, $crypt): JsonResponse {
    $selection_settings = $this->keyValue('filebrowser')->get($crypt);
    if (!empty($selection_settings)) {
      $entity_type = $selection_settings['entity_type'];
      $entity_bundle = $selection_settings['entity_bundle'];
      $field_name = $selection_settings['field_name'];
      $folder = $selection_settings['folder'];
      $all = !empty($selection_settings['all']);
      $maxLevel = $all ? TRUE : 2;
      $directory = $request->request->get('directory');
      $public_path = $this->streamWrapperManager->getViaScheme('public')->getDirectoryPath();
      $system_path = $this->cleanPath("$public_path/$folder/$directory", TRUE);
      if (!(!empty($system_path) && $this->fileSystem->realpath($system_path))) {
        $system_path = $this->getFolder($entity_type, $entity_bundle, $field_name, $system_path);
      }
      $response = $this->scan($system_path, $maxLevel);
    }
    return new JsonResponse($response ?? []);
  }

  /**
   * {@inheritDoc}
   */
  public function getFolder($entity_type, $entity_bundle, $field_name, $directory = ''): string {
    $temp = explode('-', $field_name);
    $field_name = $temp[0];
    $form_mode = 'default';
    $field_widget_settings = $this->entityTypeManager()
      ->getStorage('entity_form_display')
      ->load($entity_type . '.' . $entity_bundle . '.' . $form_mode)
      ->getComponent($field_name)['settings'];
    if (stripos($field_widget_settings["folder"], '{') !== FALSE) {
      $renderable = [
        '#type' => 'inline_template',
        '#template' => $field_widget_settings["folder"],
        '#context' => [
          'entity_type' => $entity_type,
          'entity_bundle' => $entity_bundle,
          'field_name' => $field_name,
        ],
      ];
      $field_widget_settings["folder"] = $this->renderer->render($renderable)->__toString();
    }
    $field_widget_settings["folder"] .= $directory;
    $directory = !empty($field_widget_settings["folder"]) ? DIRECTORY_SEPARATOR . $field_widget_settings["folder"] : DIRECTORY_SEPARATOR;
    // Get directory in field widget config.
    $public_path = $this->streamWrapperManager->getViaScheme('public')->getDirectoryPath();
    return $public_path . $directory;
  }

  /**
   * Get files in directory.
   *
   * {@inheritDoc}
   */
  public function scan($dir, $maxLevel = 2, $level = 0): array|object {
    $files = [];
    $level++;
    // Is there actually such a folder/file?
    if (file_exists($dir)) {
      foreach (scandir($dir) as $f) {
        if (!$f || $f[0] == '.') {
          // Ignore hidden files.
          continue;
        }
        if (is_dir($dir . '/' . $f)) {
          // The path is a folder.
          $files[$f] = NULL;
          if (!$maxLevel || $level < $maxLevel) {
            $files[$f] = $this->scan($dir . '/' . $f, $maxLevel, $level);
          }
        }
        else {
          // It is a file.
          $file_path = '/' . $dir . '/' . $f;
          $extension = pathinfo($file_path, PATHINFO_EXTENSION);
          if ($extension !== 'php') {
            $files[$f] = $file_path;
          }
        }
      }
    }
    return $files ?: (object) [];
  }

  /**
   * {@inheritdoc}
   */
  public function uploadFile(Request $request, $crypt): JsonResponse {
    $selection_settings = $this->keyValue('filebrowser')->get($crypt);
    if ($selection_settings && $this->currentUser()->hasPermission('add link file browser')) {
      $public_path = $this->streamWrapperManager->getViaScheme('public')->getDirectoryPath();
      $folder = $selection_settings['folder'];
      $directory = $request->get('path');
      $type = $request->get('type');
      $directory_upload = $this->cleanPath("$public_path/$folder/$directory", TRUE);
      $this->fileSystem->prepareDirectory($directory_upload, FileSystemInterface::CREATE_DIRECTORY | FileSystemInterface::MODIFY_PERMISSIONS);
      if (!$type) {
        $uploadedFile = $request->files->get('file');
        if (!$uploadedFile) {
          return new JsonResponse(['error' => $this->t('No files were sent.')], 400);
        }
        $extends = explode('.', $uploadedFile->getClientOriginalName());
        if (strtolower(end($extends)) === 'php') {
          return new JsonResponse(['error' => $this->t('File is not supported.')], 400);
        }
        $path_upload = $directory_upload . DIRECTORY_SEPARATOR . $uploadedFile->getClientOriginalName();
        $data = file_get_contents($uploadedFile->getPathname());
        $pathSaveFile = $this->fileSystem->saveData($data, $path_upload, FileExists::Replace);
        if ($pathSaveFile) {
          return new JsonResponse([
            'status' => 'success',
            'filename' => $uploadedFile->getClientOriginalName(),
            'path' => "/$pathSaveFile",
          ]);
        }
        else {
          return new JsonResponse(['error' => $this->t('Cannot save file.')], 500);
        }
      }
      return new JsonResponse([
        'status' => 'success',
        'path' => $directory,
      ]);
    }
    else {
      return new JsonResponse(['error' => $this->t('No permission.')], 403);
    }
  }

  /**
   * {@inheritdoc}
   */
  public function cleanPath(string $path, $isReplaceSeparatorSystem = FALSE) :string {
    $path = preg_replace('/^\/+|\/+$/', '', $path);
    $path = preg_replace('/\/+/', '/', $path);
    if ($isReplaceSeparatorSystem) {
      $path = str_replace('/', DIRECTORY_SEPARATOR, $path);
    }
    return html_entity_decode($path);
  }

  /**
   * {@inheritdoc}
   *
   * @throws \Exception
   */
  public function shareLink(Request $request, $crypt): BinaryFileResponse|Response {
    if (empty($crypt) || $crypt === 'downloaded') {
      return new Response($this->t('File downloaded'), 200);
    }
    $unPack = LZString::decompressFromEncodedURIComponent($crypt);
    if ($unPack === FALSE) {
      return new Response('Failed to decompress data', 400);
    }

    $unPack = Json::decode($unPack);

    $access = TRUE;
    if (array_key_exists('u', $unPack) || array_key_exists('r', $unPack)) {
      $access = FALSE;
      if (array_key_exists('u', $unPack)) {
        if (in_array($this->account->id(), $unPack['u'])) {
          $access = TRUE;
        }
      }
      if (array_key_exists('r', $unPack)) {
        if (!$access && array_intersect($this->account->getRoles(), $unPack['r'])) {
          $access = TRUE;
        }
      }
    }

    if ($access) {
      // Sanitize path.
      $folderFile = str_replace(['../', '..\\'], '', $unPack['p']);
      $path = urldecode($folderFile);
      $path = $this->cleanPath($path, TRUE);
      if (is_file($path)) {
        return $this->downloadFile($path);
      }
      elseif (is_dir($path)) {
        $zipPath = sys_get_temp_dir() . '/' . basename($path) . '_' . uniqid() . '.zip';
        $this->zipFolder($path, $zipPath);
        return $this->downloadFile($zipPath, TRUE);
      }
      else {
        return new Response('File not found: ' . basename($path), 404);
      }
    }
    else {
      throw new AccessDeniedHttpException('You do not have permission to access this page.');
    }
  }

  /**
   * Create zip file form directory.
   *
   * @throws \Exception
   */
  private function zipFolder($folderPath, $zipFilePath): void {
    $zip = new \ZipArchive();
    if ($zip->open($zipFilePath, \ZipArchive::CREATE | \ZipArchive::OVERWRITE) !== TRUE) {
      throw new \Exception('Can not create zip.');
    }

    $folderPath = realpath($folderPath);

    $files = new \RecursiveIteratorIterator(
      new \RecursiveDirectoryIterator($folderPath),
      \RecursiveIteratorIterator::LEAVES_ONLY
    );

    foreach ($files as $file) {
      if (!$file->isDir()) {
        $filePath = $file->getRealPath();
        $relativePath = substr($filePath, strlen($folderPath) + 1);
        $zip->addFile($filePath, $relativePath);
      }
    }

    $zip->close();
  }

  /**
   * Download file.
   */
  private function downloadFile($filePath, $deleteAfter = FALSE): BinaryFileResponse {
    $response = new BinaryFileResponse($filePath);
    $response->setContentDisposition(
      ResponseHeaderBag::DISPOSITION_ATTACHMENT,
      basename($filePath)
    );
    if ($deleteAfter) {
      $response->deleteFileAfterSend(TRUE);
    }

    return $response;
  }

  /**
   * Share page.
   *
   * @param \Symfony\Component\HttpFoundation\Request $request
   *   The request service.
   * @param string $crypt
   *   The crypt link.
   *
   * @return array
   *   A renderable array.
   */
  public function sharePage(Request $request, $crypt): array {
    $url_share = Url::fromRoute('link_filebrowser.share', ['crypt' => $crypt], ['absolute' => TRUE]);
    $redirect = $request->get('r');

    return [
      '#theme' => 'share_page',
      '#redirect' => $redirect,
      '#url' => $url_share,
      '#attached' => [
        'library' => [
          'link_filebrowser/browser.share_page',
        ],
      ],
    ];
  }

}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc