Полезности о input -ах типа file в Битрикс

Обычно народ просто ставит

<input type="file" name="file" value="файлег">

Но это не по нашему! Выглядит стандартно, да и нет никакой валидации по типу файла, если мы, к примеру, хотим загружать только файлы определённого типа.

Итак, для начала давайте подумаем, что мы хотим:

  1. Реализовать в форме input типа file, принимающий только картинки
  2. Около input -а должна быть надпись с названием файла, который мы будем загружать после выбора оного в диалоговом окне
  3. Файл-картинку из этого input-а нужно загружать в инфоблок
  4. Предусмотреть обработку ошибки, когда физический размер картинки больше установленного в php.ini

Давайте для начала реализуем пункт 2.

Как это должно выглядеть в идеале:

Joxi

Пример вёрстки: ТЫК

Листинг кода:

<!DOCTYPE html>
<html>
    <head>
        <title>Пример к статье "Полезности о input -ах типа file в Битрикс"</title>
        <meta charset="UTF-8">
        <script src="http://code.jquery.com/jquery-1.12.0.min.js" type="text/javascript"></script>
        <style>
			body {
			  font-family: "Helvetica Neue","Helvetica","Arial",sans-serif;
			  font-size: 13px;
			}
			.file-block {
				display: table;
			}
			.file-div {
				background: transparent none repeat scroll 0 0;
				border: 2px solid #c2c2c2;
				border-radius: 5px;
				color: #555555;
				cursor: pointer;
				display: table-cell;
				font-size: 13px;
				height: 27px;
				outline: medium none;
				text-align: center;
				transition: all 0.3s ease 0s;
				vertical-align: middle;
				width: 125px;
			}
			.file-name {
				color: #dc112e;
				display: table-cell;
				font-size: 13px;
				height: 27px;
				text-align: right;
				vertical-align: middle;
				width: 125px;
			}
			.hidden {
				display: none;
				visibility: hidden;
			}
        </style> 
		<script type="text/javascript">
			//обработка нажатия кнопки "обзор"
			$( document ).ready(function() {
				var browse = document.getElementById("browse");
				var browse_real = document.getElementById("browse-real");
				browse.addEventListener("click", function(e) {
							browse_real.click();
							e.preventDefault();
						  }, false);
				browse_real.addEventListener('change', function() {
				  var val = browse_real.value;
				  //в opera и chrome путь полный с косыми чертами - разделим на массив с разделителями "\" и отобразим последний элемент:
				  var mas = val.split('\\')
				  $('.file-name').html(mas[mas.length - 1]);
				});
			});
		</script>
    </head>
    <body>
        <div class="file-block">
			<div class="file-div" id="browse">Обзор</div>
			<div class="file-name">Файл не выбран</div>
			<input type="file" id="browse-real" class="hidden" name="file">
		</div>
    </body>
</html>

Окей, выбор файла работает. А как теперь сделать ограничение на приём только картинок и пихать их в инфоблок?

Переходим к реализации пункта 1 и 3.

Нам нужна форма. Обернём наш инпут формой и добавим кнопку «Отправить»:

<form method="post" action="#" id="test-form">
	<div class="file-block">
		<div class="file-div" id="browse">Обзор</div>
		<div class="file-name">Файл не выбран</div>
		<input type="file" id="browse-real" class="hidden" name="file">
	</div>
	<button id="sbm_btn" type="submit">Отправить</button>
</form>

Напишем собственно саму отправку формы на AJAX:

$(document).on('click', '#sbm_btn', function (e) {
	e.preventDefault();
	$.ajax( {
		url: '/ajax/test_form.php',
		type: 'POST',
		data: new FormData( $("#test-form")[0] ),
		processData: false,
		contentType: false,
		success: function(data) {
			if (data=='OK'){
				// здесь ставим своё уведомление о том, что сообщение отправлено
			}
			if (data=='INVALID FILE SIZE'){
				// здесь ставим своё уведомление о том, что превышен размер файла
			}
			if (data=='INVALID FILE TYPE'){
				// здесь ставим своё уведомление о том, что не тот тип файла (не картинка)
			}
		}
	}); 
});

В /ajax/test_form.php и будет производится проверка файла на тип и если это картинка — она будет загружаться в инфоблок.

Листинг test_form.php:

<?
require_once($_SERVER['DOCUMENT_ROOT'] . "/bitrix/modules/main/include/prolog_before.php");
?>
<?
//проверяем размер файла
if ($_FILES['file']['error']=='1'){
    echo 'INVALID FILE SIZE';
    die();
}

// если есть вложение
if (!empty($_FILES['file']['tmp_name'])) {    
    //здесь проверяем расширение (картинка):
    if(strripos($_FILES['file']['type'], 'image')!==false){
        // Закачиваем файл в /tmp_img
        $name = $_FILES['file']['name'];
        $uploads_dir = $_SERVER['DOCUMENT_ROOT'].'/tmp_img';
        $is_moved = move_uploaded_file($_FILES['file']['tmp_name'], "$uploads_dir/$name");
        if ($is_moved){
            // если всё ок:
            // действия...
            CModule::IncludeModule("iblock");
            $el = new CIBlockElement;
            $props = array();
            $props['IBLOCK_ID'] = 10; // ID инфоблока
            $props['ACTIVE'] = 'Y';
            $props['NAME'] = 'Картинка от '.date('d.m.Y H:i:s');
            $props['ACTIVE_FROM'] = date('d.m.Y H:i:s');
            $property_values = array();
            //PHOTO
            $property_values['PHOTO'] = CFile::MakeFileArray($_SERVER["DOCUMENT_ROOT"]."/tmp_img/".$name);
            $props['PROPERTY_VALUES'] = $property_values;
            //добавляем элемент в инфоблок:
            if($new_el = $el->Add($props)){
                echo 'OK';
            }
            // удаляем темповый файл:
            unlink ($uploads_dir."/".$name);
        }else{
            echo 'ERROR FILE MOVED';
        }
    }else{
        echo 'INVALID FILE TYPE';
    }
}
?>

Обратите внимание, что картинка будет загружаться в

$_SERVER['DOCUMENT_ROOT'].'/tmp_img

поэтому не забудьте создать эту папку и дать ей соответствующие права на запись.