Ошибка загрузки файла PHP (UPLOAD_ERR_PARTIAL) / $ _FILES имеет значение NULL или имеет пустое «tmp_name» - PullRequest
0 голосов
/ 08 мая 2019

У меня довольно распространенная проблема, и я часами читал кое-что об этом, но мне не удается ее исправить, и я схожу с ума ...

Контекст

У меня есть веб-сайт , где пользователи могут загрузить изображение на мой сервер (в общем случае из браузера iOS / Safari). Страница с формой загрузки: эта .

Бэкэнд сделан с PHP (без фреймворка). Фронт-эндом является HTML / Javascript. Это довольно старый сайт, который я сделал в 2010 году, так что это не «супер секси»! : -)

Я сделал журналы для мониторинга результатов загрузки, и я вижу, что около 30% пользовательских загрузок не удалось ... Я думаю, это не обычно!

Эти ошибки происходят из 2 источников (один и тот же пользователь, пытающийся загрузить несколько раз, может иметь сочетание этих 2 источников):

  • $_FILES['myFormFieldName'] равно NULL
  • $_FILES['myFormFieldName'] НЕДЕЙСТВИТЕЛЕН, но $_FILES['myFormFieldName']['error'] равен 3 (UPLOAD_ERR_PARTIAL) с $_FILES['xxx']['tmp_name'] и $_FILES['xx']['type'] пустым, а $_FILES['xxx']['size'] равен "0"

Эти ошибки не являются детерминированными ...

  • Когда я тестирую себя (используя то же изображение, что и у пользователя, у которого проблемы с загрузкой), у меня нет проблем
  • В своих журналах я вижу, что у некоторых пользователей всегда возникают проблемы с загрузкой, а у других - нет.
  • Я также вижу, что некоторым пользователям, у которых возникли проблемы, удалось загрузить свой файл с помощью siccess после нескольких попыток
  • У меня был контакт с одним пользователем, у которого возникли проблемы с сообщением о том, что у него появляется страница с ошибкой Safari cannot open the page because network connection was lost от Safari при попытке загрузить его изображение (всякий раз, когда он использует данные WiFi или мобильный 3G / 4G)

Код

HTML-форма для загрузки файла (ограничить загрузку пользователем 35M со стороны клиента)

    <ul class="pageitem">
        <form name="empty-custom-native" 
              enctype="multipart/form-data" 
              action="/upload.php?method=nativeUpload" 
              method="post">
            <input type="hidden" name="MAX_FILE_SIZE" value="36700160" />
            <li class="button" >
                <input type="file" name="iosImageFILE" id="iosImageFILE"/>
            </li>
        </form>
        <li class="button directUrlButton" onclick="javascript:onclickNativeUploadForm();">
            <input type="button" value="Upload" />
        </li>
    </ul>

Javascript, вызываемый HTML (используется для проверки того, что входной файл не пустой перед отправкой формы)

  function onclickNativeUploadForm(){
    if( document.getElementById('iosImageFILE').value=="" ){
      alert("Please choose an image FIRST !");
    } else{
      showPleaseWait();
      setTimeout(submitNativeUploadForm, 2000);
    }
  }

  function submitNativeUploadForm(){
      document.forms['empty-custom-native'].submit();
  }

PHP-код, управляющий загрузкой (извлечением) файла

<?php
if( isset($_FILES['iosImageFILE']) && !empty($_FILES['iosImageFILE']) ){
    $uploadStatus = $_FILES['iosImageFILE']['error'];
    if( $uploadStatus==0 ){
        // Copy source file to temp file
        if( !move_uploaded_file($_FILES['iosImageFILE']['tmp_name'], $_SERVER['DOCUMENT_ROOT']."/".$userImageTemp) ) {
            throw new Exception("fileUploadCopy");
        }

    } else{
        if( $uploadStatus==1 ){ throw new Exception("fileUploadIniSize"); }
        else if( $uploadStatus==2 ){ throw new Exception("fileUploadFormSize"); }
        else if( $uploadStatus==3 ){ throw new Exception("fileUploadPartial"); } // THIS ERROR ...
        else if( $uploadStatus==4 ){ throw new Exception("fileUploadNoFile"); }
        else if( $uploadStatus==6 ){ throw new Exception("fileUploadNoTmpDir"); }
        else if( $uploadStatus==7 ){ throw new Exception("fileUploadCantWrite"); }
        else if( $uploadStatus==8 ){ throw new Exception("fileUploadExtension"); }
        else{
            throw new Exception("fileUploadSystem");
        }
    }
} else{
    throw new Exception("fileUploadUpload"); // ... OR THIS ERROR
}

// If anything was OK, we continue here with the uploaded file copied in our working dir to do some stuff with it...
?>

Так что в моем случае у меня есть fileUploadUpload или fileUploadPartial исключений.


Исследования

Серверная часть (конфигурация php.ini)

Я проверил переменные среды PHP, относящиеся к загрузке файлов (с помощью команды ini_get), чтобы убедиться, что я не превысил максимальный размер файла или максимальное количество загрузок.

Все вроде нормально, у меня довольно щедрые ограничения, post_max_size лучше, чем upload_max_filesize. upload_tmp_dir пусто, наверное, это означает, что я использую систему по умолчанию /tmp dir?

Скажите, если вы видите проблемы или другие вещи, которые нужно проверить.

Примечание. У меня нет доступа к php.ini, но эти значения фиксируются моим хостинг-провайдером (я использую виртуальный хостинг).

file_uploads : '1'
upload_tmp_dir : ''
upload_max_filesize : '128M'
max_file_uploads : '20'
post_max_size : '130M'
max_execution_time : '300'

Клиентская часть (код HTML / JS)

MAX_FILE_SIZE меньше максимального размера файла, разрешенного моим сервером PHP.

Я использовал enctype="multipart/form-data" и method="post", как и ожидалось.

Я не делаю выгрузку файлов AJAX, просто использую Javascript для проверки пустоты входного файла перед отправкой формы с помощью JS.

Серверная часть (код PHP)

Когда я отлаживаю содержимое $_FILES['iosImageFILE'], я получаю это для ошибки fileUploadPartial (а для ошибки fileUploadUpload это ноль).

iosImageFILE = {"name":"DD292A1C-9CBF-4843-9E1C-7C815593C67A.png","type":"","tmp_name":"","error":3,"size":0}

Серверная часть (файловая система)

Я пытался проверить каталог /tmp, где должны находиться загруженные файлы, но у меня нет к нему доступа. Я хотел бы проверить, что он не «полон старых файлов tmp», но, думаю, нет.

На самом деле я создал PHP-скрипт для сканирования его содержимого с использованием var_export(scandir('/tmp')), и я вижу только некоторые sess_xxxxx файлы сеансов (около 7000 файлов).

Обновление кода

Я обновил и улучшил свой веб-сайт до https (ранее не был защищенным http) и обновил версию PHP с 5.6 до 7.0). Без каких-либо изменений при загрузке файлов.

Брандмауэр?!?

Возможно, я подозреваю, что проблема с брандмауэром у моего хостинг-провайдера (я читал, что он может блокировать некоторые вещи при загрузке файлов ...). Но мне сказали, что на моем хосте не активирован брандмауэр ...


Заключение

Я действительно не знаю, что делать дальше, чтобы исследовать и найти эту проблему.

Обратите внимание, что почти все, кто загружает файлы, приходят из браузера iOS / Safari.Я не знаю, будут ли такие же проблемы с другими ОС или браузерами ...

Я - веб-разработчик внешнего интерфейса, и я должен сообщить, что меня не устраивает такая проблема.

Любая помощь приветствуется!

1 Ответ

0 голосов
/ 17 июня 2019

Конец истории: как я подозревал, это была проблема с моим хостинг-провайдером (на ее решение ушло 1 месяц ...)

Мне не удалось получить более подробную информацию, за исключением того, что это была "проблема конфигурации Apache" и что у него есть ссылка с балансировкой нагрузки ...

...