Upload fajlova
Prilikom pravljenja aplikacija, kad tad ćete se susresti sa problemom slanja fajlova na server (upload). Kao što sam pomenuo u tekstu o slanju podataka preko POST metoda, fajlovi se na server šalju putem formi.
Forma za slanje fajlova
Da bi forma slala fajlove mora imati dodatni atribut enctype da bi opisala vrstu sadržaja koji će biti prosleđen serveru.
<form action="upload.php" method="post" enctype="multipart/form-data"> Izberi sliku: <input type="hidden" name="MAX_UPLOAD_LIMIT" value="2000000" /> <input type="file" name="slika" /> <input type="submit" value="Pošalji" /> </form>
Ovo je minimalna forma koja je potrebna da bi se neki fajl poslao na server, za primer sam uzeo formu koja bi slala sliku, naravno na vama je šta će forma da radi i čemu će da služi. Kao što sam već pomenuo, forma mora imati atribut encype sa vrednošću “multipart/form-data”, atribut method mora da bude “post”, i mora imati input element tipa “file“.
Za razliku od ostalih input elemenata, ovaj koji ima tip “file”, ne prihvata vrednost iz atributa value, pa tako nije moguće postaviti početnu vrednost. Takođe ovo polje nije moguće stilizovati tako da izgleda isto u svim browserima. U zavisnosti od browsera, promena izgleda ovog polja će biti moguća od delimične do nikakve. Jedina stvar kojom možete uticati na izgled je atribut size, kojim ćete moći prilično grubo da namestite širinu ovog polja. Takođe nećete moći da promenite tekst koji se nalazi na dugmetu, on će uvek ostati “Browse”, pa tako i lokalizacija nije moguća. Za rešenje ovog problema moraćete da potražite neka javascript ili adobe flash rešenja.
Kada izaberete neki fajl i kliknete na dugme “Pošalji”, serveru se šalju podaci, i za to vreme nemate nikakvu povratnu informaciju o napretku slanja fajla. Jednostavno kad se podaci pošalju na server, vaš browser će otići na fajl koji je naveden u akciji forme.
Ovde dolazi do malog, može se tako reći, problema, jer podaci o fajlu koji je prosleđen, se ne nalaze u POST promenljivoj kao što bi očekivali, nego se nalaze u promenljivoj FILES. FILES je takođe niz koji sadrži spisak fajlova koji su poslati serveru, ako smo imali više input type=”file” polja u formi. Svaki element FILES niza sadrži u sebi niz sa opisom fajla koji je poslat serveru. Taj niz izgleda ovako:
$_FILES['slika']['name'] $_FILES['slika']['type'] $_FILES['slika']['size'] $_FILES['slika']['tmp_name'] $_FILES['slika']['error']
Kad se fajl pošalje, ovaj niz se popuni podacima o fajlu. Sledeći korak je kontrola grešaka, da bi se uverili da je sve bilo u redu prilikom slanja, jer postoji nekoliko ograničenja vezanih za slanje fajlova.
Greške koji mogu da se pojave prilikom prenosa fajla, nalaze se u $_FILES['slika']['error'], a ispod se nalaze kodovi grešaka, konstante koje su pridružene tim vrednostima i objašnjenja.
- UPLOAD_ERR_OK (vrednost: 0) – Nema greške, upload je uspešan
- UPLOAD_ERR_INI_SIZE (vrednost: 1) – Veličina fajla je veća od ograničenja postavljenog u php.ini, parametar upload_max_filesize (podrazumevana vrednost je 2 MB).
- UPLOAD_ERR_FORM_SIZE (vrednost: 2) – Veličina fajla prelazi MAX_FILE_SIZE vrednost, koja se podešava u formi.
- UPLOAD_ERR_PARTIAL (vrednost: 3) – Fajl nije stigao kompletan na server.
- UPLOAD_ERR_NO_FILE (vrednost: 4) – Nije uploadovan fajl.
- UPLOAD_ERR_NO_TMP_DIR (vrednost: 6) – Ne postoji privremeni direktorijum. Ovu grešku verovatno možete da iskusite samo na vašem lokalnom serveru, ako ste ga sami podešavali. Greška dodata od PHP 4.3.10 i PHP 5.0.3 verzije.
- UPLOAD_ERR_CANT_WRITE (vrednost: 7) – Nije moguće zapisati fajl na disk servera, dodato od PHP 5.1.0 verzije.
- UPLOAD_ERR_EXTENSION (vrednost:
– Pogrešna ekstenzija izabrana za upload, dodato od PHP 5.2.0 verzije.
Problem maksimalne veličine fajla – UPLOAD_ERR_INI_SIZE
Da bi podesili ispravno php treba obratiti pažnju na nekoliko stvari tj stavki koje je potrebno promeniti u php.ini da bi upload radio ispravno.
- upload_max_filesize – početna vrednost je 2M, tj 2 megabajta (veličina je u bajtovima, ako nije dodata skraćenica za veličinu K – kilobajti, M – megabajti i G – gigabajti). Ovde se upisuje veličina fajla za koju očekujemo upload, ovde ne treba preterivati, stavite koliko vam je potrebno.
- post_max_size – se podešava u odnosu na upload_max_filesize, tako da bude veći, jer obično sa uploadom idu još neki podaci, pa da bi vam stiglo sve. Takođe ovde ne treba preterivati sa dodavanjem, najlakše je da stavite jedan megabajt više. Ukoliko su podaci koji dolaze na server preko POST metoda, veći od vrednosti koja je podešena u post_max_size, globalne promenljive $_POST i $_FILES će biti prazne.
- memory_limit je sledeća stavka koju ćete morati da povećate, tako da bude veća od post_max_size. Ovde možete dodeliti vrednost -1 tako da ne postoji ograničenje u količini memorije dodeljenoj PHP skripti. Generalno ovo je loša praksa, jer se može desiti da loše napisana skripta pojede svu raspoloživu memoriju i time ugrozi rad servera, za pravu vrednost nema nekog saveta, dajte vašoj aplikaciji barem 16M više nego što je post_max_size, ali ipak moraćete da odlučite sami. Ova promenljiva je samo sigurnosna mera protiv loših skripti i najbolje je da dodelite neku vrednost.
Postoje dva načina da se ovo setuje na vašem sajtu, prvi je promena vrednosti u php.ini fajlu, problem sa ovom metodom je što najčešće nećete imati pristup php.ini fajlu. Drugi metod, koji je oproban, je preko dodavanja sledeće linije u .htaccess fajl:
php_value upload_max_filesize 8M
Ako ne postoji, kreirajte ga, bitno je da on nema klasično ime sa ekstenzijom, kao što ste navikli na Windows platformi, nego ima samo ekstenziju. Zato je prilikom kreiranja ovog fajla bitno da ga nazovete sa tačkom isped, inače neće imati efekta. Fajl smestite u direktorijum gde se nalazi vaša skripta za upload.
Trajanje uploada
Sledeće dve stavke nisu direktno vezane za sam upload, ali mogu biti ograničavajući faktor pri uploadu, ponaročito većih fajlova.
- max_execution_time – predstavlja ukupno vreme koje server ostavlja vašoj skripti da se izvrši.
- max_input_time – je vreme koje se rezerviše za slanje podataka serveru.
Vreme izvršavanja skripte možete promeniti i pozivom funkcije set_time_limit.
Ograničavanje u browseru UPLOAD_ERR_FORM_SIZE
Veličinu fajla možete ograničiti i u browseru, dodavanjem MAX_UPLOAD_LIMIT hidden polja u vašoj formi. Ovo možete da stavite više kao neku preventivu, ali se ne treba oslanjati na ovu metodu, pošto je neki browseri ignorišu. Vrednost koja se nalazi u value atributu je izražena u bajtovima, i nema skraćenice (K, M, G) kao što je slučaj kod PHPa. Ova vrednost ne bi trebala biti veća od one koju ste stavili u upload_max_filesize.
Ostale greške
Ostale greške ovde neću komentarisati, jer se retko javljaju. Lično ni jednu od navedenih grešaka nisam video za sve ove godine rada sa PHP, niti su mi se klijenti žalili da su ih videli.
Upload
Ovde prikazana klasa, će vam detktovati moguće probleme, počevod toga da niste napisali ispravnu putanju da odredišnog direktorijuma, ispitati da li je u taj direktorijum dozvoljeno pisanje fajlova, do mogućnosti da rešite problem fajlova sa istim imenom, tako što ćete prepisati novi preko starog ili mu automatski dodeliti novo ime.
Ukoliko sve prođe bez grešaka u vašem direktorijumu će se naći fajl koji ste uploadovali. Takođe ova klasa će vam sredi ime fajl tako što će izbaciti sve moguće problematične karaktere i na njihovo mesto staviti znak “_” (donja crta). Ukoliko nemate nekih većih zahteva, ovde ponuđeno rešenje će vam završiti posao u svim slučajevima.
<?php
define ('UPLOAD_MISSING_DEST', -1);
define ('UPLOAD_DEST_NO_WRITABLE', -2);
define ('UPLOAD_WRONG_EXTENSION', -3);
define ('UPLOAD_FILE_EXIST', -4);
define ('UPLOAD_ERR_MOVE_FILE', -5);
class file_upload {
function getError($err, $opt='')
{
switch ($err)
{
case UPLOAD_ERR_OK: return '';
case UPLOAD_ERR_INI_SIZE: return 'The uploaded file exceeds the upload_max_filesize directive ('. ini_get('upload_max_filesize') .') in php.ini.';
case UPLOAD_ERR_FORM_SIZE: return 'The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form.';
case UPLOAD_ERR_PARTIAL: return 'The uploaded file was only partially uploaded.';
case UPLOAD_ERR_NO_FILE: return 'No file was uploaded.';
case UPLOAD_ERR_NO_TMP_DIR: return 'Missing a temporary folder.';
case UPLOAD_ERR_CANT_WRITE: return 'Failed to write file to disk.';
case UPLOAD_ERR_EXTENSION: return 'File upload stopped by extension.';
case UPLOAD_MISSING_DEST: return 'Destination directory does not exists.';
case UPLOAD_DEST_NO_WRITABLE: return 'Destination directory is not writable.';
case UPLOAD_WRONG_EXTENSION: return 'File extension is wrong, allowed: '. $opt;
case UPLOAD_FILE_EXIST: return 'File exists already.';
case UPLOAD_ERR_MOVE_FILE: return 'There was error while moving file from temp directory: '.$opt;
default: return 'Unknown upload error.';
}
}
function file_info($file_name)
{
$info = pathinfo($file_name);
if (!isset($info['filename'])) $info['filename'] = substr($info['name'],0,strrpos($file,'.'));
return $info;
}
function clean_file_name ($file_name)
{
$info = self::file_info($file_name);
$file_name = preg_replace("/[^\w]+/", "_", strtolower($info['filename']));
$file_name = trim($file_name, '_');
$file_name = preg_replace("/[__]+/", "_", $file_name);
return $file_name . '.'. $info['extension'];
}
function do_upload($form_field, $dest_path, $extensions="", $overwrite = false)
{
$error = '';
$file_name = self::clean_file_name ($_FILES[$form_field]['name']);
$full_path = $dest_path . $file_name;
$ext = pathinfo($file_name);
if ($_FILES[$form_field]['error'] > 0)
$error = self::getError($_FILES[$form_field]['error']);
elseif (!is_dir($dest_path))
$error = self::getError(UPLOAD_MISSING_DEST);
elseif (!is_writable($dest_path))
$error = self::getError(UPLOAD_DEST_NO_WRITABLE);
elseif ($extensions != '' && strpos($extensions, $ext['extension']) === false)
$error = self::getError(UPLOAD_WRONG_EXTENSION, $extensions);
elseif (file_exists($full_path))
{
if ($overwrite)
@unlink($full_path);
else
{
$i = 2;
$new = explode('.', $file_name);
while (file_exists($dest_path . $new[0].'_'.$i.'.'.$new[1])) ++$i;
$full_path = $dest_path . $new[0] .'_'. $i .'.'. $new[1];
}
}
if (empty($error))
{
if (move_uploaded_file($_FILES[$form_field]['tmp_name'], $full_path))
chmod($full_path, 0755);
else
$error = self::getError(UPLOAD_ERR_MOVE_FILE, $full_path);
}
if (empty($error))
{
$out['error'] = $error;
$out['name'] = $file_name;
$out['full_path'] = $full_path;
}
else
$out['error'] = $error;
return $out;
}
}
Da bi odradili upload, potrebno je ovu klasu pozvati na sledeći način:
$result = file_upload::do_upload('slika', 'upload/', 'gif,jpg,jpeg,gif');
Ako je sve u redu dobićete kao rezultat niz, koji se sastoji od naziva fajla, pune putanje fajla, i obaveštenja da nema greške. U slučaju grešeke dobićete niz u kome se sadrži opis greške koja se desila. Takođe ovde možete preuzeti kompletan primer.







06.10.2009 u 14:06
uu baš samo to tražio
04.01.2010 u 14:39
imam jedan prob, kad uploadam fajl nema ga na serveru, folder je prazan…?
14.01.2010 u 03:07
To sam zaboravio da napomene u tekstu, direktorijum u koji se smeštaju fajlovi mora ima mogućnost upisa fajlova.
Potrebno je u FTP programu, koji se koristi za upload nekog materijala na server, postaviti atribute na 777. Ovo je moguće uraditi i kroz direktan pristup serveru preko konzole sa komandom: chmod 777 ime_direktorijuma