Puncte:1

Este posibil să permiteți utilizatorilor anonimi să vadă un fișier temporar gestionat prin hook_file_download()?

drapel ng

Creez un sistem de previzualizare a imaginilor live pentru produse personalizabile care trebuie să trimită fișierul temporar al unui utilizator la un server la distanță.

Am un sistem bazat pe token pentru a proteja fișierul, dar problema pare să fie că fișierul este temporar. Am creat un hook_file_download() pentru a returna antetele așa cum este necesar pentru a permite accesul atunci când este aprobat, dar accesul la fișier este încă refuzat undeva.

Nu pare să fie o problemă de greutate a modulului, deoarece am făcut ca modulul meu personalizat să aibă cea mai mică greutate și am verificat prin codul de depanare că se declanșează după core file_file_download()

EDITARE: Depanarea ulterioară arată că matricea antetelor primește o valoare cheie setată la „-1” undeva după hook_file_download() și nucleul „FileDownloadController”, care este locul în care fișierul este refuzat. Aveți idei în care această valoare a antetului [0] = -1 este setată și cum să o înlocuiți?

Dacă îl reduc la elementele de bază pentru testare, așa cum se arată mai jos, anteturile „permite” sunt returnate, dar fișierul este încă blocat când este vizualizat dintr-un browser anonim:

funcția MYMODULE_file_download($uri) {

  // Verificați dacă aceasta este o descărcare de configurare.
  $scheme = StreamWrapperManager::getScheme($uri);

  dacă ($schemă == „temporar”){
    if ($fișiere = \Drupal::entityTypeManager()->getStorage('fișier')->loadByProperties(['uri' => $uri])){

      $fișier = resetare($fișiere) ?: NULL;
      
      // Accesul este permis.
      $headers = file_get_content_headers($fișier);
      returnează $headers;
    }
  }
}
Puncte:1
drapel us

Fișierele temporare sunt gestionate de file_file_download(), o implementare a hook_file_download() realizat din modulul Fișier. Codul pe care îl folosește este următorul.

  // Aflați dacă un fișier temporar este încă folosit în sistem.
  dacă ($fișier->esteTemporary()) {
    $usage = \Drupal::service('file.usage')->listUsage($file);
    if (empty($usage) && $file->getOwnerId() != \Drupal::currentUser()
      ->id()) {
      // Interzice accesul la fișierele temporare fără utilizare care nu sunt deținute de
      // același utilizator. Acest lucru previne problema de securitate pe care un fișier privat care
      // a fost protejat de permisiunile de câmp devine disponibil după utilizarea sa
      // a fost eliminat și înainte de a fi șters efectiv din sistemul de fișiere.
      // Modulele care depind de acest comportament ar trebui să facă fișierul permanent
      // in schimb.
      întoarcere -1;
    }
  }

Citirea comentariilor, care se face intenționat pentru a evita un fișier privat, protejat de permisiuni de câmp, este vizibilă după modificarea permisiunilor de câmp, dar înainte ca fișierul să fie șters.

Privind codul care invocă acel cârlig, în FileDownloadController::download() de exemplu, nu văd nicio modalitate de a evita asta, deoarece codul nu folosește hook_file_download_alter().

O soluție ar putea fi setarea acel fișier ca fiind utilizat, deoarece codul verifică că fișierul nu este utilizat, înainte de a bloca accesul.

funcția mymodule_file_download($uri) {
  if (StreamWrapperManager::getScheme($uri) == 'temporar') {
    if ($fișiere = \Drupal::entityTypeManager()->getStorage('fișier')->loadByProperties(['uri' => $uri])){
      if ($fișier = resetare($fișiere)) {
        // Accesul este permis.
        \Drupal::service('file.usage')->add($file, 'mymodule', 'unexisting_entity', 10);
        $headers = file_get_content_headers($fișier);
        returnează $headers;
      }
    }
  }
}

obisnuiam „entitate_inexistentă” și 10 ca tip de entitate și ID de entitate. Dacă aveți valori reale pentru ei, ar trebui să le folosiți.

Rețineți că FileUsageBase::add(), cel DatabaseFileUsageBackend::add() metoda părinte, schimbă fișierul în permanent, în cazul în care nu este deja.

// Asigurați-vă că un fișier folosit este permanent.
dacă (!$fișier->isPermanent()) {
  $fișier->setPermanent();
  $fișier->salvare();
} 

Când utilizarea unui fișier este redusă și devine 0, fișierul este schimbat în temporar de la FileUsageBase::delete().

// Dacă nu mai există utilizări rămase ale acestui fișier, marcați-l ca temporar,
// care are ca rezultat o ștergere prin system_cron().
$usage = \Drupal::service('file.usage')->listUsage($file);
dacă (gol ($utilizare)) {
  $fișier->setTemporary();
  $fișier->salvare();
}

Aș prefera să măresc utilizarea fișierului, în loc să fac direct un fișier permanent, deoarece scăderea utilizării fișierului nu intră în conflict cu alte module care ar putea seta același fișier ca fiind permanent.
Alternativ, aș folosi următorul cod pentru hook_file_download().

funcția mymodule_file_download($uri) {
  if (StreamWrapperManager::getScheme($uri) == 'temporar') {
    if ($fișiere = \Drupal::entityTypeManager()->getStorage('fișier')->loadByProperties(['uri' => $uri])){
      if ($fișier = resetare($fișiere)) {
        // Accesul este permis.
        dacă (!$fișier->isPermanent()) {
          $fișier->setPermanent();
          $fișier->salvare();
        }
        $headers = file_get_content_headers($fișier);
        returnează $headers;
      }
    }
  }
}

În acest caz, pentru a face din nou fișierul temporar, aș folosi următorul cod.

// Stochează referința entității fișierului în $file.
$usage = \Drupal::service('file.usage')->listUsage($file);
if (gol ($utilizare) && !$fișier->isTemporary()) {
  $fișier->setTemporary();
  $fișier->salvare();
}

Pentru a obține ceea ce doriți, ar fi, de asemenea, posibil să schimbați controlerul pentru sistem.temporar traseu, dar asta pare excesiv.

quantumized avatar
drapel ng
Mulțumesc, da, acel fragment file_file_download() este de vină. Sunt confuz cu privire la motivul pentru care nu pot folosi hook_file_download() în modulul meu mai ponderat pentru a înlocui asta.
quantumized avatar
drapel ng
Am găsit o soluție prin setarea fișierului la „isPermanent”, dar nu îmi place asta. Știți dacă acest lucru va face ca fișierele să nu fie șterse din sistem atunci când este necesar?
apaderno avatar
drapel us
`hook_file_download()` primește doar o adresă URL, nu anteturile returnate de alte implementări; dacă acesta ar fi cazul, o implementare hook ar putea trece peste decizia unei alte implementări. Codul real care le invocă doar verifică că unul dintre ele a returnat -1 ca antet; nu verifică -1 este prima valoare returnată.
apaderno avatar
drapel us
@quantumized Fișierele permanente nu vor fi eliminate în timpul procesului de colectare a gunoiului fișierelor, dar un modul le-ar putea șterge. Dacă modulul păstrează o listă de fișiere schimbate în permanentă, acest lucru ar putea fi posibil.
apaderno avatar
drapel us
Am adăugat, de asemenea, o notă despre ce se întâmplă atunci când utilizarea unui fișier este crescută: Implementarea de bază Drupal a serviciului *file.usage* face automat un fișier temporar permanent.

Postează un răspuns

Majoritatea oamenilor nu înțeleg că a pune multe întrebări deblochează învățarea și îmbunătățește legătura interpersonală. În studiile lui Alison, de exemplu, deși oamenii își puteau aminti cu exactitate câte întrebări au fost puse în conversațiile lor, ei nu au intuit legătura dintre întrebări și apreciere. În patru studii, în care participanții au fost implicați în conversații ei înșiși sau au citit transcrieri ale conversațiilor altora, oamenii au avut tendința să nu realizeze că întrebarea ar influența – sau ar fi influențat – nivelul de prietenie dintre conversatori.