Wysyłanie pliku na serwer

Przesyłanie plików za pomocą PHP jest łatwe i odbywa się zazwyczaj za pomocą formularza (zabawy ze strumieniami sobie odpuścimy). Stwórz skrypt o następującym kodzie:
<?php
echo '<pre>';
print_r($_POST);
echo '<HR>';
print_r($_FILES);
echo '</pre><HR>';
echo '<form enctype="multipart/form-data" method="post" action="a.php"><input type="file" size="32" name="plik_upload" value=""><input type="submit" name="Wyślij"></form>';
Ja nazwałem go "a.php", nazwa dowolna, pamiętaj tylko o zmianie parametru action. Jest to prosty skrypt roboczy zawierający odpowiedni formularz oraz wyświetlający zawartość tablic _POST i _FILES. Zaczynamy od formularza. By formularz mógł wysłać plik konieczny jest dodatek enctype="multipart/form-data" do taga FORM. Kolejnym elementem jest pole typu file (o dowolnej nazwie i tytule). Formularz musi mieć też oczywiście przycisk wysyłający.
Po otworzeniu skryptu w przeglądarce zobaczymy coś takiego:
upload_1
Zaznacz jakiś plik z dysku i wyślij formularz. Zobaczysz wtedy coś takiego:
upload_2
Interesuje nas tablica _FILES. Zawiera ona dane o wysłanym pliku: name - nazwa, type - typ MIME (bardzo ważne), tmp_name - nazwa pliku tymczasowego, size - rozmiar w bajtach. Nasz skrypt nie umie jeszcze ładować pliku ale zaraz się tego nauczy. Musimy po prostu przenieść/skopiować plik tymczasowy do bierzącego katalogu:
<?php

// Powyżej nasz formularz
$f = $_FILES['plik_upload'];
IF(isset($f['name']))
	{
	copy($f['tmp_name'], '/opt/lampp/htdocs/html/'.$f['name']);
	//lub
	rename($f['tmp_name'], '/opt/lampp/htdocs/html/'.$f['name']);
	//lub
	move_uploaded_file($f['tmp_name'], '/opt/lampp/htdocs/html/'.$f['name']);
	}
Wszystkie trzy sposoby (copy, rename, move_uploaded_file) powinny działać (na ładowanie plików ma wpły wiele ustawień PHP jak safe mod czy bezpośrednio zezwolenie na ładowanie plików). Omówienie kodu: zaczynamy od $f = $_FILES['plik_upload']; - po prostu podtablicę przypisujemy do zmiennej $f ($_FILES['NAZWA_POLA_FILE_Z_FORMULARZA']) by było ładniej potem jeżeli to co przypisaliśmy jest tablicą (tj. coś się wysłało) to kopiujemy plik gdzie trzeba. Dziwna ścieżka: /opt/lampp/htdocs/html/ to ścieżka katalogu do miejsca na serwerze, na naszym koncie, w którym pojawić się ma nasz plik (zobacz phpinfo). Możemy to trochę zautomatyzować:
<?php

$f = $_FILES['plik_upload'];
IF(isset($f['name']))
	{
	$patch = str_replace('a.php', '', $_SERVER['SCRIPT_FILENAME']);
	
	copy($f['tmp_name'], $patch.$f['name']);
	//lub
	rename($f['tmp_name'], $patch.$f['name']);
	//lub
	move_uploaded_file($f['tmp_name'], $patch.$f['name']);
	}
Zmienna $_SERVER['SCRIPT_FILENAME'] przechowuje całą ścieżkę katalogów od głównego do katalogu ze skryptem wraz z jego nazwą np. w tym przykładzie: /opt/lampp/htdocs/html/a.php. By mieć ścieżkę usuwamy nazwę pliku ze zmiennej i mamy ścieżkę (którą możemy dalej modyfikować itd.)

Bezpieczeństwo skryptu

Powyższy skrypt załaduje dowolny plik i jeżeli dostęp będą miały do niego niepowołane osoby to mogą np. załadować własny skrypt PHP. By ograniczyć ładowanie tylko określonych plików np. grafik wykorzystamy wartość klucza type:
<?php

$f = $_FILES['plik_upload'];
IF($f['type'] == 'image/png' or $f['type'] == 'image/jpeg' or $f['type'] == 'image/gif')
	{
	$patch = str_replace('a.php', '', $_SERVER['SCRIPT_FILENAME']);
	copy($f['tmp_name'], $patch.$f['name']);
	}
else
	{
	echo 'Niedozwolony plik';
	}
Oprócz tego warto zabezpieczyć się przed plikami o podmienionych rozszerzeniach, np:
<?php

$f = $_FILES['plik_upload'];
IF($f['type'] == 'image/png' or $f['type'] == 'image/jpeg' or $f['type'] == 'image/gif')
	{
	$x = getimagesize($f['tmp_name']);
	IF(!is_array($x) or $x[0] < 2)
		{
		die('Zły plik graficzny');
		}
	$patch = str_replace('a.php', '', $_SERVER['SCRIPT_FILENAME']);
	copy($f['tmp_name'], $patch.$f['name']);
	}
else
	{
	echo 'Niedozwolony plik';
	}
Wykorzystaliśmy funkcję PHP GetImageSize pobierającą dane o pliku graficznym. Funkcja ta zwraca tablicę z wymiarami i innymi danymi więc jeżeli nie mamy tablicy (plik nie jest grafiką) lub długość jest mniejsza od 2 pikseli to znaczy że mamy podróbkę (pliki nie-grafika o zmienionym rozszerzeniu mają rozmiar 0 na 0)
Nie zapomnij też o zabezpieczaniu takich skryptów hasłem (chyba że są to np. ładowacze awatarów itd.)

Wysyłanie wielu plików naraz

Zobacz tablicę _FILES dla skryptu:
<?php
echo '<pre>';
print_r($_POST);
echo '<HR>';
print_r($_FILES);
echo '</pre><HR>';
echo '<form enctype="multipart/form-data" method="post" action="a.php">
<input type="file" size="32" name="plik_upload[]" value="">
<input type="file" size="32" name="plik_upload[]" value="">
<input type="file" size="32" name="plik_upload[]" value="">
<input type="submit" name="Wyślij"></form>';
nazwa pola file wszędzie jest taka sama, tyle że jest tablicą - plik_upload[] (te nawiasy na końcu).
Notka: pliki nie muszą być kopiowane z tmp/ na nasze konto, możemy je np. też wysłać emailem, wystarczy klasa wysyłająca maile z załącznikiem...
RkBlog

PHP w Akcji, 14 July 2008

Comment article
Comment article RkBlog main page Search RSS Contact