Вопрос или проблема
Хочу начать с того, что я учусь и пытаюсь понять использование $_FILES
и $file_handler
, которые сводят меня с ума в этой функции для загрузки вложений из формы на фронтенде.
Что я обнаружил вчера в своем вопросе, так это то, что использование $_FILES
в одной и той же функции приводит к его перезаписи, поэтому один добрый человек предложил изменить эту переменную на что-то другое, например, $whatever
. Таким образом, оба файла могли бы быть обработаны и загружены, но, конечно, этого пока не происходит, и загружаются только файлы. У меня есть 2 поля формы с соответствующими именами:
- Для изображений:
name="moreimages"
- Для файлов:
name="morefiles"
В основном я пришел к такому коду на php:
if ($_FILES)
{
// Получаем загружаемые вложения
$images = $_FILES['moreimages'];
foreach ($images['name'] as $key => $value)
{
if ($images['name'][$key])
{
$image = array(
'name' => $images['name'][$key],
'type' => $images['type'][$key],
'tmp_name' => $images['tmp_name'][$key],
'error' => $images['error'][$key],
'size' => $images['size'][$key]
);
// Здесь я изменил переменную $_FILES на что-то другое
$my_processed_images = array("moreimages" => $image);
foreach ($my_processed_images as $image => $array)
{
$newupload = project_images($image,$pid);
}
}
}
// Получаем загружаемые вложения
$files = $_FILES['morefiles'];
foreach ($files['name'] as $key => $value)
{
if ($files['name'][$key])
{
$file = array(
'name' => $files['name'][$key],
'type' => $files['type'][$key],
'tmp_name' => $files['tmp_name'][$key],
'error' => $files['error'][$key],
'size' => $files['size'][$key],
'post_mime_type' => $files['type'][$key]
);
$_FILES = array("morefiles" => $file);
foreach ($_FILES as $file => $array)
{
$uploadfile = project_file($file,$pid);
}
}
}
}
и мои функции выглядят так
function project_images($file_handler, $pid)
{
if ($_FILES[$file_handler]['error'] !== UPLOAD_ERR_OK) __return_false();
require_once(ABSPATH . "wp-admin" . '/includes/image.php');
require_once(ABSPATH . "wp-admin" . '/includes/file.php');
require_once(ABSPATH . "wp-admin" . '/includes/media.php');
$image_id = media_handle_upload( $file_handler, $pid );
return $image_id;
}
function project_file($file_handler, $pid)
{
if ($_FILES[$file_handler]['error'] !== UPLOAD_ERR_OK) __return_false();
require_once(ABSPATH . "wp-admin" . '/includes/image.php');
require_once(ABSPATH . "wp-admin" . '/includes/file.php');
require_once(ABSPATH . "wp-admin" . '/includes/media.php');
$file_id = media_handle_upload( $file_handler, $pid );
update_post_meta($file_id,'is_prj_file','1');
return $file_id;
}
Я понимаю, что может быть проблема с моим $file_handler
, но я не знаю, как с этим справиться. Что на самом деле происходит, так это то, что отладка $more_images
возвращает null и не учитывается, а $_FILES
во втором цикле загружен вместо этого. Можете помочь мне?
ИСПРАВЛЕНИЕ
Мои поля HTML формы выглядят так:
<input id="moreimages" accept="image/png, image/jpeg, image/gif" type="file" name="moreimages[]" >
<input id="morefiles" accept=".zip,.pdf,.rar,.doc,.docx,.xls,.xlsx,.ppt,.pptx,.psd,.ai" type="file" name="morefiles[]" >
Кроме того, мой статус AJAX POST равен OK и отправляет эти параметры для moreimages
:
Content-Disposition: form-data; name="moreimages[]"; filename="Screen Shot 2016-04-05 at 16.48.10.png"
Content-Type: image/png
PNG
и эти параметры для morefiles
:
Content-Disposition: form-data; name="morefiles[]"; filename="articolo-slow-food-ararat.docx"
Content-Type: application/vnd.openxmlformats-officedocument.wordprocessingml.document
Так что, я думаю, что проблема, снова, в том, как эти данные принимаются в php.
Я переопределил что-то. Я не делал валидацию и только построил структуру для функции валидации и загрузки. Вы можете валидировать файл по вашему усмотрению.
if ($_FILES)
{
// Получаем загружаемые вложения
$images = $_FILES['moreimages'];
$errors="";
foreach ($images['name'] as $key => $value)
{
if ($images['name'][$key])
{
$image = array(
'name' => $images['name'][$key],
'type' => $images['type'][$key],
'tmp_name' => $images['tmp_name'][$key],
'error' => $images['error'][$key],
'size' => $images['size'][$key]
);
// Здесь я изменил переменную $_FILES на что-то другое
$_FILES['moreimages'] = $image;
if( is_wp_error( $moreimages = project_media_handle_upload('moreimages',$pid) ) )
$errors .= $moreimages->get_error_message();
}
}
// Получаем загружаемые вложения
$files = $_FILES['morefiles'];
foreach ($files['name'] as $key => $value)
{
if ($files['name'][$key])
{
$file = array(
'name' => $files['name'][$key],
'type' => $files['type'][$key],
'tmp_name' => $files['tmp_name'][$key],
'error' => $files['error'][$key],
'size' => $files['size'][$key],
'post_mime_type' => $files['type'][$key]
);
$_FILES['morefiles'] = $file;
if( is_wp_error( $morefiles = project_media_handle_upload( 'morefiles', $pid, 'file' ) ) )
$errors .= $morefiles->get_error_message();
}
}
if( ! empty( $errors) )
echo $errors;
}
function image_and_files_validate_handle( $file ){
// $file предоставляет все значения: размер, имя и т. д.
// условное утверждение здесь и возвращаем каждый раз фиксированный ключ с сообщением
$file['error'] = 'Файл недействителен';
return $file;
}
function file_upload_validate_handle( $file ){
// $file предоставляет все значения: размер, имя и т. д.
// условное утверждение здесь и возвращаем каждый раз фиксированный ключ с сообщением
$file['error'] = $file['name']. ' недействительный формат.';
return $file;
}
add_action( 'project_media_handle_upload', 'save_file_meta_content_id', 10, 2 );
function save_file_meta_content_id( $fid, $type ){
if( $type == 'file')
update_post_meta($fid,'is_prj_file','1');
}
function project_media_handle_upload( $file_id, $pid, $type= "image" ){
$action = 'image_upload_action'; // изменение пользовательского имени действия для легкости понимания
if( $type !== 'image')
$action = 'file_upload_action';
if( function_exists('check_upload_size') )
add_filter( "{$action}_prefilter", 'check_upload_size'); // стандартный фильтр wordpress для проверки размера загрузки
add_filter( "{$action}_prefilter", 'image_and_files_validate_handle'); // обе условные проверки для изображений и файлов
add_filter( "file_upload_action_prefilter", 'file_upload_validate_handle');
require_once(ABSPATH . "wp-admin" . '/includes/image.php');
require_once(ABSPATH . "wp-admin" . '/includes/file.php');
require_once(ABSPATH . "wp-admin" . '/includes/media.php');
$result = media_handle_upload( $file_id, $pid, array(), array(
'test_form' => false,
'action' => $action
));
if( ! is_wp_error($result) )
do_action( 'project_media_handle_upload', $result, $type );
return $result;
}
Все были очень полезны, и я хочу СКАЗАТЬ СПАСИБО, ребята, за то, что помогли мне. Проблема, похоже, действительно заключалась в переменной $_FILES, которая перезаписывала себя в двух циклах. После нескольких попыток я нашел решение, которое работает для меня и позволяет загружать как изображения, так и файлы.
if ($_FILES)
{
// Сначала я объявил основные переменные
$images = $_FILES['moreimages'];
$files = $_FILES['morefiles'];
// Затем я проверяю, пустые ли они. Вот и всё.
if(!empty($images)) {
foreach ($images['name'] as $key => $value)
{
if ($images['name'][$key])
{
$image = array(
'name' => $images['name'][$key],
'type' => $images['type'][$key],
'tmp_name' => $images['tmp_name'][$key],
'error' => $images['error'][$key],
'size' => $images['size'][$key]
);
$_FILES = array("moreimages" => $image);
foreach ( $_FILES as $image => $array ) {
if ( $_FILES[$image]['error'] !== UPLOAD_ERR_OK ) __return_false();
require_once( ABSPATH . "wp-admin" . '/includes/image.php' );
require_once( ABSPATH . "wp-admin" . '/includes/file.php' );
require_once( ABSPATH . "wp-admin" . '/includes/media.php' );
$image_id = media_handle_upload( $image, $pid );
update_post_meta( $pid, 'project_image',$image_id);
}
}
}
}
if(!empty($files)) {
foreach ($files['name'] as $key => $value)
{
if ($files['name'][$key])
{
$file = array(
'name' => $files['name'][$key],
'type' => $files['type'][$key],
'tmp_name' => $files['tmp_name'][$key],
'error' => $files['error'][$key],
'size' => $files['size'][$key]
);
$_FILES = array("morefiles" => $file);
foreach ( $_FILES as $file => $array ) {
if ( $_FILES[$file]['error'] !== UPLOAD_ERR_OK ) __return_false();
require_once( ABSPATH . "wp-admin" . '/includes/image.php' );
require_once( ABSPATH . "wp-admin" . '/includes/file.php' );
require_once( ABSPATH . "wp-admin" . '/includes/media.php' );
$file_id = media_handle_upload( $file, $pid );
update_post_meta( $file_id, 'is_prj_file', '1');
}
}
}
}
}
Возможно, этот код не совсем эффективен и идеален, но он выполняет свою задачу. Кроме того, в нем все еще нет серверной валидации файлов, которую я собираюсь реализовать позже, как было предложено ранее.
Ответ или решение
Доброго времени суток!
Я понимаю, что вы столкнулись с проблемой при работе с массивом $_FILES
в функции загрузки файлов и изображений через форму на фронтенде. Давайте разберем вашу реализацию и предложим решение.
Проблема
Ваша основная проблема заключается в том, что вы пытаетесь обрабатывать файлы в одном и том же цикле, что может привести к перезаписи содержимого массива $_FILES
, который вы используете для проверки загружаемых файлов. Это является причиной того, что некоторые файлы не обрабатываются должным образом.
Решение
Предлагаю улучшить ваш код, чтобы он стал более чистым и понятным. Вместо того чтобы перезаписывать массив $_FILES
, я предлагаю отдельно обрабатывать изображения и документы, не заменяя его. Вы можете использовать временные массивы для упрощения управления данными.
Обновлённый Код
Вот переработанный вариант вашего кода:
if ($_FILES) {
// Получаем файлы изображений
$images = $_FILES['moreimages'];
if (!empty($images) && is_array($images['name'])) {
foreach ($images['name'] as $key => $value) {
if ($images['name'][$key]) {
$image = array(
'name' => $images['name'][$key],
'type' => $images['type'][$key],
'tmp_name' => $images['tmp_name'][$key],
'error' => $images['error'][$key],
'size' => $images['size'][$key]
);
// Временный массив для хранения данных о изображении
$temp_files = array('moreimages' => $image);
$_FILES = $temp_files;
// Обработка загрузки изображения
if ($_FILES['moreimages']['error'] === UPLOAD_ERR_OK) {
require_once(ABSPATH . 'wp-admin/includes/image.php');
require_once(ABSPATH . 'wp-admin/includes/file.php');
require_once(ABSPATH . 'wp-admin/includes/media.php');
$image_id = media_handle_upload('moreimages', $pid);
if (is_wp_error($image_id)) {
// Обработка ошибок
echo $image_id->get_error_message();
}
}
}
}
}
// Получаем файлы документов
$files = $_FILES['morefiles'];
if (!empty($files) && is_array($files['name'])) {
foreach ($files['name'] as $key => $value) {
if ($files['name'][$key]) {
$file = array(
'name' => $files['name'][$key],
'type' => $files['type'][$key],
'tmp_name' => $files['tmp_name'][$key],
'error' => $files['error'][$key],
'size' => $files['size'][$key]
);
// Временный массив для хранения данных о файле
$temp_files = array('morefiles' => $file);
$_FILES = $temp_files;
// Обработка загрузки файла
if ($_FILES['morefiles']['error'] === UPLOAD_ERR_OK) {
require_once(ABSPATH . 'wp-admin/includes/image.php');
require_once(ABSPATH . 'wp-admin/includes/file.php');
require_once(ABSPATH . 'wp-admin/includes/media.php');
$file_id = media_handle_upload('morefiles', $pid);
if (is_wp_error($file_id)) {
// Обработка ошибок
echo $file_id->get_error_message();
} else {
update_post_meta($file_id, 'is_prj_file', '1');
}
}
}
}
}
}
Примечания
- Проверка ошибок: Я добавил проверки на ошибки, чтобы вы могли видеть, если что-то пошло не так во время загрузки.
- Подключение файлов: Убедитесь, что требуемые файлы (
image.php
,file.php
иmedia.php
) загружаются каждый раз, когда вы вызываете функцию загрузки, чтобы избежать ошибок. - Валидация файлов: Как вы отметили, валидация файлов ещё не реализована. Рекомендуется добавить проверки на допустимый тип и размер файлов для повышения безопасности вашего приложения.
Это должно позволить вам корректно загружать как изображения, так и другие файлы без перезаписи массива $_FILES
. Если у вас есть дополнительные вопросы, не стесняйтесь обращаться!