Исходники
Статьи
Языки программирования
.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 В результате выполнения данного блока программы, поля, которые содержат файл,
будут сохранены на диск в папку заданную константой |
Форум Программиста
Новости Обзоры Магазин Программиста Каталог ссылок Поиск Добавить файл Обратная связь Рейтинги
|