Статьи

Как использовать Flash для загрузки файлов с PHP

Пользователь добавил контент; это ядро ​​сети.   Начиная с Flickr и заканчивая YouTube, вы можете загружать свой собственный контент, чтобы делиться им с более широкой аудиторией, — это действие, которое происходит по всему миру, круглосуточно.   Задача, однако, не без сложностей, и для каждого сайта она выполняется по-разному, иногда с большим успехом, чем у других. 

В этой статье будет рассказано, как загружать контент в PHP, сначала из формы HTML, а затем из формы на основе Flash.   Мы изучим проблемы, с которыми вы столкнетесь, и предложим решения с акцентом на клиента. 

Загрузите соответствующий исходный код для этой статьи (~ 8 КБ)

 

HTML-форма с загрузкой файлов

Чтобы загрузить контент со страницы HTML, вам сначала понадобится страница HTML.   HTML предоставляет несколько конструкций для представления формы загрузки, большинство из которых предназначены для попадания внутрь тега FORM.   Если вы хотите загрузить контент из HTML-формы, вам нужно помнить определенные атрибуты.

Атрибут «action» тега FORM должен указывать на страницу PHP, которая будет обрабатывать фактическую загрузку.   Мы увидим пример этого позже в статье.   «Метод», используемый для отправки файла, должен быть «POST».   Вы можете указать значение «имя» в форме, если вы собираетесь добавить какие-либо дополнительные сценарии.   Наконец, и самое главное, это «enctype»,   который должен быть установлен как «multipart / form-data».

<form
action="upload.php"
method="post"
enctype="multipart/form-data"
name="frmupload">

<p>
Name:
<input type="text" name="txtname" id="txtname">
</p>

<p>
Description:<br>
<textarea
name="txtdesc"
id="txtdesc"
cols="45"
rows="5"></textarea>
</p>

<p>
Image file:
<input type="file" name="imgfile" id="imgfile">
</p>

<p>
<input
type="submit"
name="btnsubmit"
id="btnsubmit"
value="Submit">
</p>

</form>

 

Вы можете использовать любые другие элементы формы внутри тега FORM, которые вы могли использовать в прошлом для отправки дополнительной информации. Большинство из них примут форму INPUT, и поле выбора файла не отличается.   Чтобы дать пользователю возможность выбрать файл, вы указываете тег INPUT с атрибутом «type», установленным в «file».   Атрибут «name» здесь важен, так как он понадобится вам для ссылки на содержимое файла, как только оно попадет в PHP на сервере.

 

PHP скрипт для получения файла

Вы можете быть склонны думать, что обработка входящего файла — сложная задача, требующая большого количества PHP-кода.   Однако основы могут быть достигнуты всего несколькими строками кода.   Входящий файл будет сохранен во временном каталоге сервера, как определено в файле «php.ini».   Как только запрос будет выполнен, файл будет удален.   Это означает, что по мере поступления файла сначала необходимо переместить его в более постоянное место.

<?php

$uploaddir =
$_SERVER['DOCUMENT_ROOT'] .
'/upload/images/';
$uploadfile =
$uploaddir .
basename( $_FILES['imgfile']['name'] );

move_uploaded_file(
$_FILES['imgfile']['tmp_name'],
$uploadfile );

print "Got:<br/>";

foreach( $_POST as $ind => $val )
print $ind . ': ' . $val . '<br/>';

print "Upload complete.";

?>

 

Если вы решите переместить файл, это может означать медленное начало изучения процесса загрузки файла или быстрый успех.   Вы можете только переместить файл туда, где есть доступ к серверу PHP, и вы захотите убедиться, что путь существует в первую очередь.   Проверьте разрешение вашего сервера PHP и каталога назначения, чтобы убедиться, что все они могут общаться друг с другом.

Входящий файл и некоторая информация о нем хранятся в ассоциативном массиве PHP $ _FILES.   Как и следовало ожидать, под термином «массив» PHP может обрабатывать несколько загрузок файлов в одной форме.   Чтобы получить доступ к файлам в массиве, вы используете имя, которое вы дали полю в форме HTML, поэтому этот шаг был так важен.   В качестве альтернативы вы можете выбрать итерацию входящих файлов, используя также конструкцию «для каждого».

На данный момент у нас есть один или несколько входящих файлов, и мы знаем, как получить доступ к информации о них.   Мы также знаем, что нам нужно переместить их, если мы хотим, чтобы файлы оставались более одного запроса. 

PHP предоставляет функцию «move_uploaded_file ()» для перемещения файла в более постоянное место.   Функция принимает два аргумента.   Первый аргумент — это ссылка на файл, который вы хотите переместить.   Вы будете ссылаться на ассоциативный массив, используя имя поля из формы HTML и свойство «tmp_name», чтобы получить имя файла, хранящееся во временном каталоге PHP.   Второй аргумент — это абсолютный путь, включая целевое имя файла, куда файл будет перемещен.

Это все, что нужно.   Код выше всего из пятнадцати (15) строк.   Передача файла с клиента на сервер не может быть проще.   Если вы были программистом в течение какого-то времени, вы будете знать, однако, это действительно, где начинаются проблемы.   Чтение страниц справочника PHP по функции move_uploaded_file () выявит многие из этих проблем.   Далее мы рассмотрим некоторые конкретные проблемы.

 

Проблемы с загрузкой файлов

ПРИМЕЧАНИЕ: я собираюсь смотреть в основном на клиентскую сторону — как пользователь взаимодействует с операцией загрузки файла.
  Следует отметить, однако, что этот пример кода загрузки файла является просто примером.
  Есть много соображений по поводу безопасности PHP / сервера, о которых я не собираюсь рассказывать.
  Пожалуйста, подумайте дважды, прежде чем развертывать этот точный код на общедоступном сервере.

 

Обновление страницы

Загрузка файла и в большинстве случаев приводит к обновлению страницы.   Большинство пользователей привыкли ждать обновления страницы в эти дни, но это не значит, что мы должны заставлять их ждать.   Эта проблема только усугубляется загрузкой файла, так как пользователю придется ждать на той же странице файла для загрузки и только затем получать новую страницу в ответ — и ждать, пока она загрузится.   Не идеальный пользовательский опыт, и вам нужно убедиться, что вы учитываете, давая пользователю знать, что происходит.

Смотреть и чувствовать

Одна из первых вещей, с которыми вы можете столкнуться, это как контролировать внешний вид элемента управления выбором файла.   Проблема состоит в том, что конкретный внешний вид элемента управления выбором файлов управляется реализацией браузера.   На первый взгляд это может показаться не большой проблемой, но когда вы посмотрите на то, как отображается элемент управления в разных операционных системах, вы начинаете понимать проблему.

Размер файла

Какой размер файла вы хотите, чтобы ваши пользователи могли загружать?   Это становится проблемой для клиента, потому что большие файлы занимают время, а сети не всегда надежны.   Это также проблема на сервере, потому что файл «htaccess» захочет указать, что можно загрузить.   Вы не хотите, чтобы пользователь загружал файл только для того, чтобы обнаружить, что он слишком большой.   Или, что еще хуже, ваш сервер взорвался, потому что пользователь отправил слишком большой файл.   Это только усугубляется, когда пользователи хотят отправлять более одного файла одновременно.

Расширение файла

Хотя вы можете позволить пользователю выбрать файл, поиск информации об этом файле на клиенте перед отправкой проблематичен.   Расширение файла не означает, что вы получаете файл, который вы ожидали.   Вполне возможно, что вы ожидаете файл JPEG, но кто-то со злым умыслом просто переименовал EXE в JPG.   Сторонний EXE на вашем сервере просто предлагает попытку взлома.

Фильтрация файлов

Размышления о расширениях файлов напрашиваются на вопрос об использовании диалога выбора файлов для ограничения того, какие типы файлов выбраны.   К сожалению, браузер не предлагает способ ограничения выбора файлов.   Это означает, что кто-то, даже без злого умысла, может случайно выбрать исполняемый файл, который может повредить вашей инфраструктуре.   Это также оставляет мысленный пробел, когда вы можете захотеть JPEG, но пользователь думает, что он хочет загрузить ZIP-архив изображений JPEG.

Индикация прогресса

Я упоминал ранее, что размер файла является проблемой, которую нужно знать при загрузке файлов.   Сами пользователи также становятся нетерпеливыми.   Большинство интернет-провайдеров предоставляют высокую скорость загрузки, но медленную скорость загрузки.   Традиционный способ решить эту проблему — отключить кнопку отправки, чтобы пользователи не могли отправлять свой контент дважды.   Было бы гораздо эффективнее сообщить пользователям о ходе их загрузки, но, опять же, браузеры не предоставляют доступ к информации о прогрессе.

Выбор нескольких файлов

Браузеры также не предоставляют диалоговое окно выбора файлов, позволяющее выбрать несколько файлов одновременно.   Если вы хотите, чтобы пользователь мог выбрать несколько файлов, вам нужно предоставить для них несколько полей HTML INPUT.   Это означает, что пользователи должны многократно открывать диалоговое окно выбора файла и могут случайно выбрать один и тот же файл дважды.   Возвращаясь к вопросу о размере файла, вы также можете не захотеть, чтобы пользователь отправлял все эти файлы с помощью одной формы, поэтому общее решение заключается в ограничении количества полей ввода.

 

Решения для загрузки файлов во Flash

Тогда кажется, что процесс загрузки файлов в браузер полон проблем.   Именно поэтому разработчики склонны так сильно бороться с этой темой.   Хорошая новость заключается в том, что я не привел вас так далеко, чтобы оставить вас без ответов.   И есть ответы на все эти проблемы.   В частности, использование Adobe Flash Player дает вам возможность решить все эти проблемы за один раз.

Обновление страницы

Когда вы используете Flash для форм и загрузки файлов, единственная причина, по которой страница должна обновляться, это то, что вы этого хотите.   По умолчанию Flash Player отправит соответствующие данные, в данном случае один или несколько файлов, а затем представит разработчику событие, чтобы сообщить им, когда сервер завершил обработку и вернул его в качестве ответа — вы даже можете изящно обрабатывать, когда файл Ошибка загрузки в логике вашего приложения.

protected function doSubmitClick( event:Event ):void
{
var dest:URLRequest = new URLRequest( UPLOAD_URL );
var params:URLVariables = new URLVariables();

params.txtname = txtname.text;
params.txtdesc = txtdesc.text;

dest.method = URLRequestMethod.POST;
dest.data = params;

file.addEventListener(
ProgressEvent.PROGRESS,
doFileProgress );

file.upload( dest, IMAGE_FIELD );
}

 

Смотреть и чувствовать

Когда дело доходит до Flash, вы получаете контроль над тем, как все выглядит.   Настолько, что поначалу это может пугать.   К счастью, в мире есть дизайнеры.   А если дизайнер недоступен для вас, есть фреймворки, такие как Flex, которые бесплатны и открыты.   Контроль над внешним видом не ограничивается загрузкой файлов.   Как вы хотите, чтобы поле и кнопка выбора файла выглядели полностью на ваше усмотрение.   Ниже приведен пример выбора файла с помощью Flash.

<!-- Skin this to look like anything -->
<s:Button
x="207"
y="232"
label="Browse"
click="doBrowseClick( event )"/>

. . .

 


protected function doBrowseClick( event:Event ):void
{
if( file == null )
{
file = new FileReference();
file.addEventListener( Event.SELECT, doFileSelect );
file.addEventListener(
DataEvent.UPLOAD_COMPLETE_DATA,
doFileComplete );
file.addEventListener( Event.COMPLETE, doLoadComplete );
}

file.browse( [new FileFilter( "Image File", "*.jpg" )] );
}

 

Размер файла

Основным классом является FileReference, который дает вам гораздо больше, чем просто возможность выбрать файл.   Мы поговорим об этом позже, но изначально мы беспокоились о размере файла или файлов, которые выбрал пользователь.   В случае FileReference есть свойство, которое сообщит вам размер файла в байтах.   Имейте в виду, что один мегабайт не совсем 1 000 000 байтов — это 1 048 576 байтов.   Сделайте математику, и вы можете сказать пользователю, что его файл слишком большой, прежде чем он отправит его.

protected function doFileSelect( event:Event ):void
{
if( file.size < TWO_MEGABYTES )
{
inRange = true;
}
}

 

Расширение файла

Если расширение — это просто набор символов — символов, которые могут маскировать что-то более вредоносное или просто некорректное — тогда вы, вероятно, захотите взглянуть на содержимое файла.   Flash Player позволяет загружать содержимое локального файла и просматривать.   Является ли файл, выбранный пользователем, JPEG?   Загрузите байты файла, возьмите выборку и убедитесь, что это не исполняемый файл в одежде изображения.

protected function doLoadComplete( event:Event ):void
{
var marker:String = null;

marker = file.data.readUnsignedByte().toString( 16 );
marker = marker + file.data.readUnsignedByte().toString( 16 );

if( marker.toUpperCase() == JPEG_MARKER )
{
isJpeg = true;
} else {
isJpeg = false;
}
}

 

Фильтрация файлов

Используя локальный доступ к файлам, вы теперь можете точно определить, какой тип файла отправляет пользователь, прежде чем отправлять содержимое.   Это не означает, что мы не должны облегчать нашим пользователям выбор правильного файла.   При использовании метода FileReference.browse () вы можете передать массив объектов FileFilter.   В результате появляется диалоговое окно, которое уменьшает беспорядок в файлах, которые вы не хотите выбирать.   Нет случайного выбора ZIP-архива изображений вместо ряда актуальных файлов изображений.


protected function doBrowseClick( event:Event ):void
{
if( file == null )
{
file = new FileReference();
file.addEventListener( Event.SELECT, doFileSelect );
file.addEventListener(
DataEvent.UPLOAD_COMPLETE_DATA,
doFileComplete );
file.addEventListener( Event.COMPLETE, doLoadComplete );
}

file.browse( [new FileFilter( "Image File", "*.jpg" )] );
}

 

Индикация прогресса

Поскольку у вас есть абсолютный контроль над пользовательским интерфейсом, который будет последовательно отображаться обратно в Internet Explorer 6 и более поздних версиях, теперь вы можете легко и надежно включать и отключать элементы управления, чтобы пользователи не пытались отправить форму дважды.   FileReference также запускает события, когда файл передается по сети.   Вы также получаете уведомление на клиенте, когда весь файл прибыл на сервер.  Теперь вы можете точно сказать пользователю, как далеко продвинулась его загрузка. 

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

protected function doFileProgress( event:ProgressEvent ):void
{
var percent:Number = Math.floor(
( event.bytesLoaded / event.bytesTotal )
* 100 );

txtprogress.text =
event.bytesLoaded +
" of " +
event.bytesTotal +
" (" +
percent +
"%)";
}


protected function doFileComplete( event:DataEvent ):void
{
file.removeEventListener(
ProgressEvent.PROGRESS,
doFileProgress );

txtdesc.text = event.data;

isjpeg = false;
txtname.text = "";
imgfile.text = "";
btnsubmit.enabled = false;
}

 

Выбор нескольких файлов

С помощью Flash вы также можете выбрать несколько файлов в одном диалоговом окне, не открывая его несколько раз, тем самым требуя, чтобы пользователь сохранял умственную очередь того, что он ранее выбрал.   FileReferenceList содержит массив объектов FileReference, выбранных пользователем из их системы. 

Поскольку вы можете получить доступ к информации о размере выбранных файлов, теперь вы можете выяснить, насколько велик будет общий размер загрузки, но здесь она становится интересной.   Flash Player позволяет загружать отдельные файлы из списка одновременно, а не отправлять все файлы одновременно.   Это позволяет вам эффективно управлять процессом загрузки, информировать пользователя и контролировать влияние на вашу инфраструктуру.

protected function doBrowseMulti( event:MouseEvent ):void
{
if( files == null )
{
files = new FileReferenceList();
files.addEventListener( Event.SELECT, doFilesSelect );
}

files.browse();
}

protected function doFilesSelect( event:Event ):void
{
var total:Number = 0;

for( var f:Number = 0; f < files.fileList.length; f++ )
{
total += FileReference( files.fileList[f] ).size;
}

total = total / ONE_MEGABYTE;

lbltotal.text = total.toFixed( 2 );
}

 

Вывод

Flash Player является вездесущим, и он иногда получает повсеместно плохое отношение со стороны сообщества разработчиков.   Понятно, что плохие программисты делают плохие вещи с программным обеспечением, но реальность такова, что браузеры не реализуют все, что вы хотите или нуждаетесь, чтобы обеспечить эффективную загрузку файлов (среди прочего).   И хотя HTML 5 находится на горизонте, он также все еще не охватывает большинство из этих проблем в предложенной в настоящее время форме.

API плагина браузера был разработан по причине — чтобы обеспечить функциональность браузерам, где стандарты не имеют.   Flash Player — вездесущий плагин для браузера, который вы можете использовать, чтобы сделать задачи загрузки файлов более удобными для вас и более элегантными для ваших пользователей.   Как видно из приведенных выше фрагментов кода, для сбора значительного количества энергии требуется всего лишь небольшое усилие.   И все тот же PHP-скрипт остается неизменным.