Lato w pełni, więc możemy się pokusić o połączenie przyjemnego z pożytecznym. Będziemy prawie robić psikusy, czyli rzucać wodorostami w upatrzoną najładniejszą dziewczynę (lub chłopaka) i uciekać gdzie pieprz, albo choćby trzcina rośnie. Co prawda bardziej przyjemne będzie to dla nas, a nie dla naszego celu, ale jak powiedziałem, będzie to prawie psikus. Tak naprawdę będziemy chcieli dwa analogicznie działania przenieść na płaszczyznę programowania.
Dziel i rządź...? Nieee... Rzucaj i uciekaj!
Dziś pokażę Ci jeden ze sposobów na wymuszenie pobrania pliku, czyli po prostu "wyrzucenie" go do przeglądarki wraz z przekierowaniem. Jasnym jest, że wykonanie tych dwóch operacji w PHP z wykorzystaniem funkcji header, nie jest możliwe. Albo możemy wykonać przekierowanie, albo wymusić download. Skoro wymusimy download, to nie zrobimy przekierowania. Jeśli jednak zrobimy przekierowanie, to możemy z pomocą pewnej sztuczki wykonać download. I będzie to odbywać się dokładnie w takiej kolejności - najpierw przekierowanie, potem download. Odwrotnie byłoby kiepawo.
No dobra, czyli przekierowanie wykonamy w znany sposób:
header('Location: /index.php');
Przekierowujemy na nasz główny plik. Oczywiście może to być inny plik, ale musimy w nim obsłużyć download. Możesz teraz pomyśleć, że przecież wystarczy dodać zmienne jako query string, które odbierzemy w index.php i będziemy wiedzieć, że musimy zrobić download. Niby tak, ale jeśli użytkownik odświeżyłby taką stronę, to znów wykonalibyśmy download, a przecież nie zawsze o to chodzi, bo nie chcemy generować w kółko tego samego pliku lub też sedno jest w tym, aby plik wygenerować jednokrotnie.
Trzeba w jakiś inny sposób przekazać informację do pliku index.php, że należy wysłać plik do przeglądarki. Naszym wyczekiwanym, nadmorskim zachodem Słońca będzie sesja. To w niej zapiszemy sobie informację o tym, że mamy wyrzucić plik. Jednak po przekierowaniu nie możemy jednocześnie wygenerować kodu HTML naszej strony i wykonać download, bo przecież otrzymamy nielubianą informację headers already sent. I teraz naszym oczom ukazuje się drugi, niemniej piękny zachód Słońca, mianowicie metoda meta refresh udająca prawdziwe przekierowanie HTTP.
<meta http-equiv="refresh" content="0; url=jakis_URL">
Pewnie najczęściej ten tag używany jest po prostu do przekierowania na inną, w tym inną wizualnie, podstronę. Ale przecież nie jest powiedziane, że można go użyć tylko do tego. Możemy przekierować na dowolny adres, również taki, w którym poinformujemy nasz skrypt, że ma wyrzucić plik do przeglądarki.
Tak więc po przekierowaniu wygenerujemy kod nowej podstrony, tam w zależności od istnienia zmiennej w sesji dodamy metatag. W metatagu będzie adres z parametrem, który przekieruje przeglądarkę na ten sam skrypt, a ten wygeneruje tylko i wyłącznie plik, bez kodu HTML.
Jak działa przekierowanie z downloadem? Tak. (Po wpisaniu wartości w pole otrzymasz plik z tąże zwartością).
Na mecie.
Działa to tak:
- jeśli nie ma żadnych danych z $_POST, ani $_GET, to generujemy nasz formularz (czyli stronę startową),
- jeśli mamy dane z $_POST, to:
- pobieramy je,
- generujemy losową nazwę pliku,
- zapisujemy do pliku dane,
- nazwę pliku zapisujemy do sesji,
- wykonujemy przekierowanie i kończymy,
- jeśli mamy dane w sesji, to generujemy w stronie dodatkowo metatag refresh z URL na nasz skrypt i parametrem informującym, że trzeba pobrać dane, niech to będzie parametr getfile,
- jeśli mamy w $_GET parametr getfile, to:
- wyrzucamy plik do przeglądarki,
- usuwamy plik,
- usuwamy nazwę pliku z sesji (w ten sposób odświeżając stronę nie będzie generowany metatag refresh, a więc i download),
Oczywiście stroną startową (przed przekierowaniem) nie musi być formularz. Najważniejsze jest to, aby przed redirect zapisać w sesji informację o pliku, po przekierowaniu wygenerować stronę z metatagiem refresh (jeśli jest informacja w sesji), i obsłużyć pobieranie pliku na podstawie URL z metatagu wraz z usuwaniem informacji z sesji. Samo generowanie pliku można wykonać w momencie zapisu informacji do sesji lub ad hoc - w trakcie żądania pobierania.
Prosty kod, który użyłem dla tego przykładu, wygląda następująco:
<?php
session_start();
if($_SERVER['REQUEST_METHOD'] === 'POST'){
if(!empty($_POST['name'])){
$filename = uniqid();
file_put_contents($filename, $_POST['name']);
$_SESSION['filename'] = $filename;
header('Location: index.php');
exit();
}
}
else{
if(isset($_GET['getfile'])){
header('Content-Type: text/plain');
header("Content-Transfer-Encoding: Binary");
header("Content-disposition: attachment; filename=plik.txt");
readfile($_SESSION['filename']);
unlink($_SESSION['filename']);
unset($_SESSION['filename']);
exit;
}
}
?>
<!DOCTYPE html>
<html lang="pl">
<head>
<title></title>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8" />
<?php
if(!empty($_SESSION['filename'])){
?>
<meta http-equiv="Refresh" content="0; url=index.php?getfile"/>
<?php
}
?>
</head>
<body>
<?php
if(isset($_SESSION['filename'])){
echo "Pobieranie pliku rozpoczęło się!";
}
else{
?>
<form method="post">
<input type="text" name="name"/>
<input type="submit" value="Pobierz"/>
</form>
<?php
}
?>
</body>
</html>
Tym zdaniem kończę nasze dzisiejsze psikusowanie. Proponuję przekierować się na plażę i ściągnąć...
Do przeczytania!
Przydatne linki:
O meta refresh w Wikipedii.