Technika ukrytej ramki
Sposób ten polega na wysyłaniu pliku nie poprzez główne okno przeglądarki, a ukrytą ramkę. Po zakończeniu uploadu ukryta ramka może dać odpowiedź, że transfer się zakończył. Metoda ta jest najbardziej popularna, jednakże jest też najbardziej prymitywna. Nie możemy obsłużyć błędów transferu pliku, jedyna możliwość to odesłanie przez przeglądarkę informacji o pomyślnym wysłaniu pliku lub komunikacie błędu walidacji. Jeśli podczas transferu wydarzy się jakiś inny błąd, np. połączenie z serwerem zostanie zerwane, nie możemy na to zareagować.
Implementacja
Schemat algorytmu tej techniki:
1. Formularz z danymi jest wysyłanie nie do głównego okna przeglądarki, a do ukrytej ramki (ustawić atrybut "target")
2. Żądanie z ukrytej ramki jest obsługiwane przez skrypt php
3. Generowany jest kod html, w którym w zależności czy upload się powiódł, czy nie wykonywana jest odpowiednia funkcja javascript ramki nadrzędnej.
4. Użytkownik widzi rezultat swojej akcji po skutkach funkcji js wywołanej przez ukrytą ramkę.
Formularz html (plik index.html):
[HTML]
<html>
<head>
<script type="text/javascript">
//funkcja zwrotna wywoływana jeśli upload zakończy się sukcesem
function uploadSuccess()
{
alert("Upload zakończył się sukcesem");
}
//funkcja zwrotna wywoływana jeśli upload zakończy się błędem
function uploadError()
{
alert("Upload zakończył się błędem");
}
</script>
</head>
<body>
<form action="upload.php" id="form" target="hiddenFrame" enctype="multipart/form-data" method="post">
<input type="file" name="file" />
<input type="submit" value="wyślij" />
</form>
<!-- ukryta ramka, przez którą idzie żądanie post -->
<iframe width="0" height="0" frameborder="0" name="hiddenFrame" id="hiddenFrame"></iframe>
</body>
</html>
Obsługa uploadu po stronie serwera (plik upload.php)
[PHP]
<?php $valid = true; if($_SERVER['REQUEST_METHOD'] != 'POST') { $valid = false; } else { $file = $_FILES['file']; { { $valid = false; } } else { $valid = false; } } ?> <html> <head> <script type="text/javascript"> window.onload = function() { //odpowied? w postaci wywo?ania funkcji ramki nadrz?dnej <?php if($valid): ?> parent.uploadSuccess(); <?php else: ?> parent.uploadError(); <?php endif; ?> }; </script> </head> <body> </body> </html>
Istnieją darmowe biblioteki, które realizują asynchroniczne wysyłanie plików poprzez ukrytą ramkę, przykładowo Ajax upload, czy plugin(y) do jQuery (np. ten).
Wykorzystanie flasha + javascript (swfupload)
Niestety, delikatnie mówiąc, nie jestem zbyt mocny w AS, więc upload z wykorzystaniem flasha zaprezentuje na przykładzie znanej biblioteki - swfupload.
Pobieramy najnowszą stabilną wersję. Swfupload ma mnóstwo konfigurowalnych opcji, dzięki tej bibliotece w prosty sposób można zrobić progress bar, kolejnowanie wysyłania plików, wyświetlanie prędkości uploadu i inne ciekawe efekty. Ja zajmę się najprostszym wykorzystaniem tej biblioteki.
Implementacja
Plik index.html
[HTML]
<html>
<head>
<script type="text/javascript" src="layout/swfupload.js"></script>
<script type="text/javascript">
window.onload = function(){
var swf = new SWFUpload({
upload_url: "upload.php",
flash_url: "layout/swfupload.swf",
file_post_name: "file",
button_width: "100px",
button_height: "30px",
button_text: "<span>prześlij plik</span>",
button_placeholder_id: "swfupload",
button_action: SWFUpload.BUTTON_ACTION.SELECT_FILE,
file_queue_limit: 1,
//ustawienie funkcji zwrotnych
//wywoływana gdy upload się rozpoczyna
upload_start_handler: function(file){
document.getElementById("files").innerHTML = "";
return true;
},
//wywoływana gdy upload zakończy się sukcesem
upload_success_handler: function(file){
document.getElementById("files").innerHTML = "Uploadowano "+file.name;
},
//wywoływana gdy upload zakońćzy się błędem
upload_error_handler: function(){
document.getElementById("files").innerHTML = "Błąd podczas wysyłania pliku "+file.name;
},
//wywoływana gdy zostanie wybrany plik z okna dialogowego
file_dialog_complete_handler: function(){
swf.startUpload();
}
});
}
</script>
</head>
<body>
<div id="swfupload"></div>
<div id="files"></div>
</body>
</html>
Plik upload.php może być ten sam co w poprzednim przykładzie, jedynie dobrze usunąć kod html. Więcej bardziej zaawansowanych przykładów można znaleźć na stronie domowej projektu.
Wykorzystanie appletu Java
Istnieje biblioteka będącem appletem Javy, która służy do wysyłania plików na serwer, nazywa się ona... jupload. Jednakże nie będe jej wykorzystywał w moim przykładzie. Napiszę bardzo prymitywny applet.
Implementacja
Najpierw zastanówmy się w jaki sposób ma dokonywać się ten upload:
1. Użytkownik wchodzi na stronę www, w jego przeglądarce uruchamia się applet (musi on być podpisany cyfrowo, aby miał odpowiednie uprawnienia dostępu do systemu plikowego)
2. Użytkownik naciska przycisk "wybierz plik", pokazuje mu się swingowe okno dialogowe wyboru pliku, wybiera któryś z plików ze swojego dysku twardego
3. Applet nawiązuje połączenie ze zdalnym serwerem (może być ten sam serwer, na którym applet się znajduje)
4. Applet przygotowywuje i wysyła żądanie POST do zdalnego serwera, wcześniej dołączając do ciała żądania wcześniej wybrany przez użytkownika plik
5. Aplikacja serwerowa (skrypt php, servlet itp.) otrzymuje żadanie POST, dokonuje zapisu pliku na dysku i odsyła jakiś komunikat (np. 200 w razie sukcesu lub 500 w razie błędu)
6. Applet odczytuje kod odpowiedzi i wyświetla odpowiedni komunikat (przesyłanie powiodło się / nie powiodło się)
Kod będzie bardzo uproszczony, nie będe obsługiwał błędów, nie będzie też całego kodu źródłowego gdyż nie chodzi o szczegóły, a o ideę. Cały kod źródłowy wraz z plikiem *.jar zostanie udostępniony.
[JAVA]
//pkt. 2 - ukazanie okna dialogowego, użytkownik wybiera plik { //utworzenie strumienia wejściowego do przesyłanego pliku //pkt. 3 - otwarcie połączenia ze zdalnym serwerem //pkt. 4 - konfiguracja połączenia, ustawienie odpowiednich nagłówków i cała żądania, wysłanie żądania con.setUseCaches(false); con.setDefaultUseCaches(false); con.setRequestMethod("POST"); con.setRequestProperty("Connection", "Keep-Alive"); //przesyłamy plik, więc trzeba zmienić typ danych con.setRequestProperty("Content-Type", "multipart/form-data; boundary="+boundary); con.setDoOutput(true); con.setDoInput(true); //dołączanie pliku do ciała żądania out.writeBytes("--"+boundary+endl); out.writeBytes("Content-Disposition: form-data; name=\"file\"; filename=\"" + URLEncoder.encode(f.getName()) +"\"" + endl); out.writeBytes("Content-Type: application/octet-stream"+endl); out.writeBytes(endl); //właściwe dołączanie bajtów pliku byte[] bytes = new byte[1024]; int read = 0; while((read = in.read(bytes)) != -1) { out.write(bytes, 0, read); } out.writeBytes(endl+"--"+boundary+"--"+endl); out.flush(); //wysłanie żądania con.connect(); //pkt. 5 - teraz aplikacja serwerowa otrzymała żądanie i je obsługuje //pkt. 6 - sprawdzenie kodu odpowiedzi, i ustawienie odpowiedniego komunikatu (text to obiekt JLabel) if(con.getResponseCode() == 200) text.setText("przesłano plik: "+f.getName()); else text.setText("błąd podczas przesyłania pliku: "+f.getName()); //zamknięcie strumieni, połączenia itp. }
Kod źródłowy: pobierz
Podsumowanie
Asynchroniczny upload plików jest możliwy na wiele sposobów, omówiłem jedynie 3 najbardziej popularne. W erze gdzie praktycznie każdy ma zainstalowany plugin flasha (a napewno większy odsetek użytkowników niż plugin javy), wykorzystanie swfupload wydaje się dobrym wyborem, zwłaszcza że daje on naprawdę duże możliwości. Jednakże należy pamiętać, że flash jest inaczej obsługiwany przez różne systemy operacyjne (tutaj java góruje :P) i mogą pojawić się problemy. Przesyłanie plików przez ukrytą ramkę jest najbardziej prymitywnym, ale też najbardziej uniwersalnym sposobem - jedynie należy napisać kod javascript, który będzie działał pod każdą popularną przeglądarką (użycie jQuery niemalże to gwarantuje).

Komentarze (0)
Brak komentarzy.