|
Исходники
Статьи
Языки программирования
.NET Delphi Visual C++ Borland C++ Builder C/С++ и C# Базы Данных MySQL MSSQL Oracle PostgreSQL Interbase VisualFoxPro Веб-Мастеру PHP HTML Perl Java JavaScript Протоколы AJAX Технология Ajax Освоение Ajax Сети Беспроводные сети Локальные сети Сети хранения данных TCP/IP xDSL ATM Операционные системы Windows Linux Wap Книги и учебники
Скрипты
Магазин программиста
|
HTML File UploadНа этой страничке вы узнаете как закачать файл на веб-сервер, используя HTML. Перед тем как приступить к разработке, желательно ознакомиться с RFC1867: Form-based File Upload in HTML, в котором описаны форматы передачи файлов в HTML. КлиентЧтобы закачать файл на сервер, Вам нужно использовать тэг Вы должны установить в тэг Например, давайте создадим следующий HTML файл, назовем его
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=windows-1252"> <title>DWD File Upload</title> </head> <body> <form method="POST" action="/scripts/upload.dll" enctype="multipart/form-data"> <p><input type="checkbox" name="checkbox" value="ON">CheckBox Test <p>RadioBox Test: <input type="radio" value="ON" checked name="radiobox">ON <input type="radio" value="OFF" name="radiobox">OFF <p>TextBox Test: <input type="text" name="text" size="20"> <p>File2 Test: <input type="file" name="myfile1" size="20"> <p>File2 Test: <input type="file" name="myfile2" size="20"> <p>File2 Test: <input type="file" name="myfile3" size="20"> <p> <input type="submit" value="Submit"> <input type="reset" value="Reset" name="B2"> </form> </body> </html> Пример 1 Итак, мы создали форму которая содержит элементы Загрузите этот файл браузером, например, набирите
и примерно следующий контент: ----7d015813802c4 Content-Disposition: form-data; name="checkbox" ON ----7d015813802c4 Content-Disposition: form-data; name="radiobox" ON ----7d015813802c4 Content-Disposition: form-data; name="text" ...текст из элемента текст... ----7d015813802c4 Content-Disposition: form-data; name="myfile1"; filename="C:\image.gif" Content-Type: image/gif ...содержимое файла 1... ----7d015813802c4 Content-Disposition: form-data; name="myfile2"; filename="C:\test.exe" Content-Type: application/octet-stream ...содержимое файла 2... ----7d015813802c4 Content-Disposition: form-data; name="myfile3"; filename="C:\text.txt" Content-Type: text/plain ...содержимое файла 3... ----7d015813802c4-- Пример 2 Где СерверНа стороне сервера, для приема данных, мы будем использовать ISAPI приложение, которое сейчас и создадим. Запускаем Delphi, создаем с помощью Delphi IDE новый проект (мы создали ISAPI
DLL, вы можете создать как ISAPI, так и CGI) и создаем обработчик
Приступим к написанию кода. Создадим обработчик события
procedure TWebModule1.WebModule1WebActionItem1Action(Sender: TObject;
Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
begin
if (Pos('multipart/form-data', LowerCase(Request.ContentType)) > 0) and
(Pos('boundary', LowerCase(Request.ContentType)) > 0) then
begin
...
end
else
Response.Content := 'Content-type is not "multipart/form-data".';
end;
Пример 3 Определим ...
var
Boundary: string;
Header: TStrings;
begin
...
Header := TStringList.Create;
try
ExtractHeaderFields([';'], [' '], PChar(Request.ContentType), Header,
False, False);
Boundary := Header.Values['boundary'];
finally
Header.Free;
end;
...
Пример 4 Для того, чтобы прочитать переданные клиентом данные, нужно прочитать
свойство AllContent := Request.Content; ByteToRead := Request.ContentLength - Length(AllContent);Далее следует зарезервировать память для буфера, для того чтобы экономнее расходовать память, ограничим максимальный размер буфера константой MaxReadBlockSize. Определим весь поток данных, переданный клиентом:
const
MaxReadBlockSize = 8192;
...
var
Boundary, BufferStr, AllContent: string;
Header: TStrings;
ByteToRead, ReadedBytes, RSize: Integer;
Buffer: PChar;
begin
...
AllContent := Request.Content;
ByteToRead := Request.ContentLength - Length(AllContent);
try
while ByteToRead > 0 do
begin
RSize := MaxReadBlockSize;
if RSize > ByteToRead then
RSize := ByteToRead;
GetMem(Buffer, RSize);
try
ReadedBytes := Request.ReadClient(Buffer^, RSize);
SetString(BufferStr, Buffer, ReadedBytes);
AllContent := AllContent + BufferStr;
finally
FreeMem(Buffer, RSize);
end;
ByteToRead := Request.ContentLength - Length(AllContent);
end;
// и возвратим клиенту справочную информацию
Response.Content := Response.Content + Format('ContentType = %s<br>' +
'ContentLength = %d<br>Readed Bytes = %d<br>Boundary = %s<hr>',
[Request.ContentType, Request.ContentLength, Length(AllContent),
boundary]);
...
except
on E: Exception do
Response.Content := Response.Content + '<p>' + E.Message;
end;
...
Пример 5 Итог: мы прочитали весь переданный контент и присвоили его переменной
Следующим этапом необходимо полученный контент разобрать по частям. Для этого напишем функцию
которая будет запрашивать разделитель ----7d015813802c4 Content-Disposition: form-data; name="radiobox" ON ----7d015813802c4 Content-Disposition: form-data; name="text" ...текст из элемента текст... ----7d015813802c4 Content-Disposition: form-data; name="myfile1"; filename="C:\image.gif" Content-Type: image/gif ...содержимое файла 1... ----7d015813802c4 Content-Disposition: form-data; name="myfile2"; filename="C:\test.exe" Content-Type: application/octet-stream ...содержимое файла 2... ----7d015813802c4 Content-Disposition: form-data; name="myfile3"; filename="C:\text.txt" Content-Type: text/plain ...содержимое файла 3... ----7d015813802c4-- Пример 6 объект
а переменная После четвертой обработки будет: ----7d015813802c4 Content-Disposition: form-data; name="myfile2"; filename="C:\test.exe" Content-Type: application/octet-stream ...содержимое файла 2... ----7d015813802c4 Content-Disposition: form-data; name="myfile3"; filename="C:\text.txt" Content-Type: text/plain ...содержимое файла 3... ----7d015813802c4-- Пример 7 объект
а переменная Код функции приведен в Примере 8: function TWebModule1.ReadMultipartRequest(const Boundary: string;
ARequest: string; var AHeader: TStrings; var Data: string): string;
var
Req, RHead: string;
i: Integer;
begin
Result := '';
AHeader.Clear;
Data := '';
if (Pos(Boundary, ARequest) < Pos (Boundary + '--', ARequest))
and (Pos(Boundary, ARequest) = 1) then
begin
Delete(ARequest, 1, Length(Boundary) + 2);
Req := Copy(ARequest, 1, Pos(Boundary, ARequest) - 3);
Delete(ARequest, 1, Length(Req) + 2);
RHead := Copy(Req, 1, Pos(#13#10#13#10, Req)-1);
Delete(Req, 1, Length(RHead) + 4);
AHeader.Text := RHead;
for i := 0 to AHeader.Count - 1 do
if Pos(':', AHeader.Strings[i]) > 0 then
AHeader.Strings[i] := Trim(Copy(AHeader.Strings[i], 1,
Pos(':', AHeader.Strings[i])-1)) + '=' + Trim(Copy(AHeader.Strings[i],
Pos(':', AHeader.Strings[i])+1, Length(AHeader.Strings[i]) -
Pos(':', AHeader.Strings[i])));
Data := Req;
Result := ARequest;
end
end;
Пример 8 Теперь осталось только вызвать данную процедуру в цикле и сохранить данные на диск. Определим константу const
UploadPath = 'C:\temp\upload\';
...
var
AllContent, Boundary, Data: string;
Header, HList: TStrings;
OutStream: TFileStream;
begin
...
if Request.ContentLength = Length(AllContent) then
while Length(AllContent) > Length('--' + Boundary + '--' + #13#10) do
begin
Header := TStringList.Create;
HList := TStringList.Create;
try
AllContent := ReadMultipartRequest('--' + Boundary, AllContent,
Header, Data);
ExtractHeaderFields([';'], [' '],
PChar(Header.Values['Content-Disposition']), HList, False, True);
if (Header.Values['Content-Type'] <> '') and (Data <> '') then
begin
OutStream:=TFileStream.Create(UploadPath +
ExtractFileName(HList.Values['filename']), fmCreate);
try
try
OutStream.WriteBuffer(Pointer(Data)^, Length(Data));
Response.Content := Response.Content +
Format('<p>File <b>%s</b> saved.',
[ExtractFileName(HList.Values['filename'])]);
except
Response.Content := Response.Content +
Format('<p>Unable to save file <b>%s</b>.', [UploadPath +
ExtractFileName(HList.Values['filename'])]);
end;
finally
OutStream.Free;
end
end
else
Response.Content := Response.Content + Format('<p>Field <b>%s</b> = %s',
[HList.Values['name'], Data]);
finally
Header.Free;
HList.Free;
end;
end;
...
Пример 9 В результате выполнения данного блока программы, поля, которые содержат файл,
будут сохранены на диск в папку заданную константой |
Форум Программиста
Новости
Обзоры
Магазин Программиста
Каталог ссылок
Поиск
Добавить файл
Обратная связь |