Upload i download plików - jak to działa od zaplecza
Data: 2019-02-04, autor: Michał MisztalJak wysłać plik na serwer za pomocą formularza wie każdy. Natomiast nie każdy wie jak to wszystko działa od środka. Kiedyś dodawałem kilka plików do pobrania na stronę, a strona nie posiadała mechanizmu który by w tym pomagał. Musiałem zrobić to ręcznie, a całość wyglądała tak
- zmiana nazw plików na takie bez znaków specjalnych i polskich
- pozbycie się wielkich liter
- sprawdzenie czy nazwa jest unikalna - jeśli nie to do korekty
- przesłanie pliku na serwer za pomocą klienta ftp
- aktualizacja strony o wspomniany plik
Chwilę to trwało bo plików było ok 30. "Szybciej, szybciej". Odpowiadam, że szybciej się nie da. No to atak z drugiej strony "to jak to możliwe, że starsze panie z urzędów to szybciej robią". Ręce mi opadły. Starsze panie z urzędów robią to szybciej bo operują na aplikacji do tego przygotowanej. Kiedy zaproponowałem, że coś takiego mogę wdrożyć i tutaj ale trzeba będzie za to zapłacić to otrzymałem odpowiedź, że sami sobie to mogą zrobić bo są darmowe szablony. Cóż - nic mądrego nie dodam - jedynie link opisujący efekt Krugera-Dunninga.
Strona ma działać następująco - przez prosty formularz należy dodać plik, plik ma być opisany tytułem i, opcjonalnie, zawartością. Całość tworzę akurat w CodeIgniterze, więc opiszę akurat to.

No i tak - litanię którą napisałem wyżej wypadałoby teraz oskryptować. Dołączamy odpowiedni kod
$this->load->helper(array('url'));//wymagane przez bibliotekę uploads
$config['upload_path'] = '../uploads/zapytania/';//folder dla plików
$config['allowed_types'] = 'pdf';//powiedzmy, że akceptujemy jedynie PDF-y
$config['max_size'] = 10000;
$config['encrypt_name'] = true;//przypisujemy plikowi losową nazwę
$this->load->library("upload", $config);
A dump tablicy na dane niech wygląda tak
CREATE TABLE `zapytania_ofertowe` (
`id` int(11) NOT NULL,
`created_at` timestamp NOT NULL DEFAULT current_timestamp(),
`updated_at` timestamp NOT NULL DEFAULT current_timestamp(),
`title` varchar(250) COLLATE utf8_polish_ci NOT NULL,
`alias` varchar(250) COLLATE utf8_polish_ci NOT NULL,
`content` text COLLATE utf8_polish_ci NOT NULL,
`filename_new` varchar(100) COLLATE utf8_polish_ci NOT NULL,
`filename_original` varchar(100) COLLATE utf8_polish_ci NOT NULL,
`active` tinyint(1) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_polish_ci;
Zapewne ktoś zapyta po co zmieniać nazwę pliku. Przedstawię zatem taki zrzut ekranu

Ano po to to wszystko, żeby odfajkować pierwsze trzy pozycje z mojej listy. Skrypt przypisze unikalną nazwę bez znaków specjalnych i polskich liter. Powtórzę jeszcze raz - nazwa będzie unikalna. Dzięki czemu na stronie downloadu można pobrać nawet kilkaset plików o tej samej nazwie a każdy będzie unikalny (nie zrobię tego bo to byłoby zbyt okrutne).
Teraz uzupełnimy przedostatni warunek - czyli ładowanie pliku na serwer.
if(!$this->upload->do_upload('file'))
{
//kod wykonywany w przypadku błędu np
$this->load->view('error/form_error', ['message' => 'Błąd podczas ładowania pliku']);
}else{
//kod wykonywany w przypadku powodzenia
$this->load->view('success', ['message' => 'Polecenie zostało wykoname poprawnie']);
}
Punkt ostatni - listowanie pliku - widok (lista uzupełnia się sama). Kontroler i model już daruję.
<?php foreach ($data as $link) : ?>
<li><a href="/zapytania-ofertowe/download/<?= $link->id ?>"><?= $link->title ?></a></li>
<?php endforeach; ?>
Żeby pobrać plik wykorzystamy kod
public function DownloadById($id)
{
if(!empty($id))
{
$this->load->helper("download");
$file = $this->Zapytania_Model->GetFileById($id);
force_download(
$file->filename_original,
file_get_contents('../uploads/zapytania/' . $file->filename_new, true)
);
}
}



Mam nadzieję, że pewne rzeczy udało mi się wyjaśnić. A przynajmniej cykl życia pliku na serwerze od uploadu do downloadu. I, że nie wszystko to tak pięknie i różowo wygląda jak by się mogło zdawać. Nie mówię, że jest to jakieś skomplikowane, ale, że zawsze za tym stoi czyjaś praca a tą warto szanować.