Основы закачки файлов Согласно протоколу HTTP файлы можно закачивать двумя способами:
Наиболее распространеный POST метод, PUT метод в настоящее время почти не используется. Чтобы броузер передал файл нужно поместить на страницу такой HTML код
<form enctype="multipart/form-data" method="post" action="upload_script.php"> <input type="hidden" name="MAX_FILE_SIZE" value="1000"> Выберите файл: <input name="имя_поля" type="file"> <input type="submit" value="Послать файл"> </form>
ОБЯЗАТЕЛЬНО нужно указывать <form enctype="multipart/form-data" method="post"...> и очень желательно <input type="hidden" name="MAX_FILE_SIZE" value="XXXX"> причем ДО поля ввода файла. Когда эти условия выполнены, можно писать скрипт который будет обрабатывать закачку файлов.
<?php function doUpload($field_name, $overwrite=false, $uniquename=false){ if (!is_array($field_name)) $field_name=Array($field_name); #-------- FILE UPLOAD ----------------- // место хранения файлов $storage="/home/www/public_html/uploads/";
// маленькие проверки на будущие глюки $flag = (bool) ini_get("safe_mode"); if ($flag||(!strstr($_SERVER['SERVER_SOFTWARE'], 'win'))){ if (getmyuid()!=fileowner($storage)){ die("Safe mode uncompatibililty. Check owner for '".$storage"'"); } } // разрешенные для закачки расширения (типы) файлов $allowed=array( 'jpg', 'gif', 'png', 'pdf', 'doc', 'txt', 'rtf' );
foreach ($field_name as $field_i){
// максимальный размер файла. В любом случае он не может быть // больше чем upload_max_filesize=??M в php.ini (2Мб) // а также post_max_size=??M (8Мб) $maxsize=61440; // 60Kб
// считываем имя закачиваемого файла $filename=$_FILES[$field_i]['name'];
// считываем размер закачиваемого файла $filename=$_FILES[$field_i]['size'];
// считываем расширение файла $fileext=strtolower(substr(strrchr($filename,"."),1));
// запрещаем закачку неразрешенных типов, например PHP скриптов!! if(!in_array($fileext, $allowed)){ die("Недопустимый тип файла"); }
// запрещаем закачку слишком больших файлов if($filesize>$maxsize){ die("Слишком большой файл"); }
// считываем имя файла, который закачан во временную папку // upload_tmp_dir= в файле php.ini $tmpfname=$_FILES[$field_i]['tmp_name'])
// исправляем имя файла, удаляем недопустимые символы, пробелы. $filename = ereg_replace("[^a-z0-9._]", "", str_replace(" ", "_", str_replace("%20", "_", strtolower($name))));
if ($filename=""){ die("Недопустимое имя файла. Только английские буквы, цифры и '_'!"); }
// полный путь к закачке файла $filepath=$storage; if ($uniquename){ $filepath=$filepath.time()."_"; } $filepath=$filepath.$filename;
if (is_uploaded_file($tmpfname) {
// если $overwrite!=true проверяем нету ли уже такого файла if (!$overwrite){ if (file_exists($filepath)){ die("Файл с именем <b>".$filename."</b> уже существует. Переименуйте файл или удалите его с сервера"); } }
move_uploaded_file($tmpfname, $filepath) or die("Ошибка закачки файла: ".$filename); // Если пользователь Апача и FTP разные, например nobody и pupkin, // то чтобы иметь доступ по FTP (по умолчанию выставляется 0600) // поставьте 0644 или 0666 если хотите также перезаписывать по FTP @chmod($filepath, 0644); } } } #------------- END FILE UPLOAD ---------- }
// вызвать функцию doUpload('имя_поля');
// закачать несколько файлов сразу doUpload(Array('имя_поля1','имя_поля2'));
// если нужно перезаписывать существующий файл doUpload('имя_поля', true);
// если нужно сохранить существующий файл // будет создано новое имя, н: pic.jpg -> 989181984_pic.jpg doUpload('имя_поля', false, true); ?>
PHP версии 3 не имел функции move_uploaded_file() поэтому до выхода четвертой версии исполльзовалась функция copy() которая до сих пор находится в документации и пользуется популярностью. КРАЙНЕ НЕЖЕЛАТЕЛЬНО использовать copy() при закачке файлов, т.к. возможны многие глюки. copy() вообще не будет работать при включенном open_basedir!! В safe_mode=On чтобы использовать copy() нужно установить на временную папку того же ВЛАДЕЛЬЦА что и выполняет скрипт, тоесть аплоад будет невозможно делать если у вас несколько пользователей (как и должно быть в случае виртуальных доменов). Кроме того copy() не выполняет проверку файла на существование, не возвращает
Возможные глюки
- file_uploads=Off в php.ini. Закачка файлов запрещена
- Нету прав на $storage="/home/www/public_html/uploads/". Измените chown на пользователя под которым запущен скрипт или поставьте на папку chmod 0777
- Целевая директория имеет другого владельца чем под которым запущен PHP, когда safe_mode=On. Это повсеместно распространенный случай для шарового хостинга, когда пользователь Апача для примера www или nobody, тогда как доступ по FTP, например, для pupkin. Выхода два:
- Долбить службу поддержки для настройки одинаковых юзеров на FTP и Apache (для вашего виртуального домена).
- Папку для загрузки создать ИЗ скрипта под Апачем и поставить на неё 'chmod 0777'. Тогда Вы сможете работать из скриптов обходя safe_mode запреты и редактировать файлы по FTP.
- Нету прав на upload_tmp_dir=; (настройка в php.ini). Поставьте chmod 0777 на эту папку.
- Файлы могут быть испорченными если под Апачем запущены некоторые модули, например mod_charset (Также известный как Russian Apache). Выключите его для определенных файлов:
<Files upload.php><br> CharsetDisable On<br> </Files>
- Не закачиваются большие файлы. Причин может быть несколько, если не выполняется хоть одно из условий, файл не закачается:
- Размер файла больше $_POST['MAX_FILE_SIZE']
- Размер файла больше upload_max_filesize=2M (php.ini)
- Размер файла больше post_max_size=8M (php.ini)
- Размер файла больше LimitRequestBody (httpd.conf)
- Исчерпана дисковая квота или на upload_tmp_dir= или на целевую директорию
- Время выполнения скрипта превысило max_execution_time= (php.ini)
- Время выполнения скрипта превысило Timeout 30 (httpd.conf)
- Время выполнения скрипта превысило таймаут для CGI (Консоль IIS)
- Пользователь сидит за прокси который запрещает передачу
|