ru en uk

  авторизация

(044) 362 48 16   (098) 294 41 60


   Цены

Основы закачки файлов


Согласно протоколу HTTP файлы можно закачивать двумя способами:

  • POST методом
  • PUT методом

Наиболее распространеный 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($filepath0644);
      }
     }
}
#------------- END FILE UPLOAD ----------
}

// вызвать функцию
doUpload('имя_поля');

// закачать несколько файлов сразу
doUpload(Array('имя_поля1','имя_поля2'));

// если нужно перезаписывать существующий файл
doUpload('имя_поля'true);

// если нужно сохранить существующий файл
// будет создано новое имя, н: pic.jpg -> 989181984_pic.jpg
doUpload('имя_поля'falsetrue);
?>


PHP версии 3 не имел функции move_uploaded_file() поэтому до выхода четвертой версии исполльзовалась функция copy() которая до сих пор находится в документации и пользуется популярностью. КРАЙНЕ НЕЖЕЛАТЕЛЬНО использовать copy() при закачке файлов, т.к. возможны многие глюки. copy() вообще не будет работать при включенном open_basedir!! В safe_mode=On чтобы использовать copy() нужно установить на временную папку того же ВЛАДЕЛЬЦА что и выполняет скрипт, тоесть аплоад будет невозможно делать если у вас несколько пользователей (как и должно быть в случае виртуальных доменов). Кроме того copy() не выполняет проверку файла на существование, не возвращает

Возможные глюки



  1. file_uploads=Off в php.ini. Закачка файлов запрещена
  2. Нету прав на $storage="/home/www/public_html/uploads/". Измените chown на пользователя под которым запущен скрипт или поставьте на папку chmod 0777
  3. Целевая директория имеет другого владельца чем под которым запущен PHP, когда safe_mode=On. Это повсеместно распространенный случай для шарового хостинга, когда пользователь Апача для примера www или nobody, тогда как доступ по FTP, например, для pupkin. Выхода два:

    • Долбить службу поддержки для настройки одинаковых юзеров на FTP и Apache (для вашего виртуального домена).
    • Папку для загрузки создать ИЗ скрипта под Апачем и поставить на неё 'chmod 0777'. Тогда Вы сможете работать из скриптов обходя safe_mode запреты и редактировать файлы по FTP.

  4. Нету прав на upload_tmp_dir=; (настройка в php.ini). Поставьте chmod 0777 на эту папку.
  5. Файлы могут быть испорченными если под Апачем запущены некоторые модули, например mod_charset (Также известный как Russian Apache). Выключите его для определенных файлов:

    <Files upload.php><br>
    CharsetDisable On<br>
    </Files>

  6. Не закачиваются большие файлы. Причин может быть несколько, если не выполняется хоть одно из условий, файл не закачается:

    • Размер файла больше $_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)

  7. Пользователь сидит за прокси который запрещает передачу
  8. Вы использовали ДРУГОЙ способ закачки, чем в этой статье, например сокращенный синтаксис, при том что register_globals=Off или старая версия PHP или, ещё хуже - использовали copy() вместо move_uploaded_file().
  9. Неправильно работает $HTTP_POST_FILES[$field_name]['type']. Это не глюк PHP, этот параметр передаётся броузером, так что НИКОГДА не полагайтесь на него.
  10. Проблемы с НЕброузерной закачкой файла (Не URI encoded форма). В большинстве случаев для этого понадобится использовать $HTTP_RAW_POST_DATA
  11. Проблемы с закачкой файлов нулевой длины. Суть проблемы не в том что файлы не закачиваются, а в том что невозможно определить закачался ли файл на самом деле. Многие люди проверяют статус закачки через $HTTP_POST_FILES[$field_name]['size'] но как в случае когда файл не закачался, так и в случае пустого файла, переменная будет равна 0. Если пользователь сам напечатает имя несуществующего файла в поле броузера, он передастся как файл нулевой длины. Проверить это средствами PHP нельзя.
  12. magic_quotes_gpc=On и stripslashes на Win платформе создаст проблемы с получением имен файлов, так например $HTTP_POST_FILES[$field_name]['size'] всё-таки должен содеражть двойные бек-слеши.
  13. Неправильные параметры переданы в move_uploaded_file(). Там должно быть что-то вроде:

    <?php
    // правильный синтаксис
    move_uploaded_file(
    '/var/php_tmp_upload/userfile.jpg',
    '/home/pupkin/public_html/userfile.jpg'
    );

    // неправильный синтаксис
    move_uploaded_file(
    'userfile.jpg',
    '/home/pupkin/public_html/userfile.jpg'
    );
    ?>




 
Введение в PHP5
29.05.2007
Работа с базами данных
29.05.2007
Постраничный вывод результата
29.05.2007