Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > Delphi программирование > Работа с сетью в Delphi
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 25.02.2008, 20:03   #1
ActiveX
Пользователь
 
Регистрация: 30.01.2008
Сообщений: 14
По умолчанию Отправка файла POST-запросом на PHP-скрипт...

Добрый день. Необходимо решить следующую задачу - есть следующий простейший PHP-скрипт:

Код:
<?
$ip=getenv("REMOTE_ADDR");
$filename=$_POST['fname'];
$data=$_POST['data'];
$fp=fopen($ip."_".$filename, 'w');
fwrite($fp, $data);
fclose($fp);
?>
На него нужно POST запросом отправит файл(тип файла может быть любой, например RAR архив, EXE, DLL и т.д.) из Delphi приложения. После долгих поисков в сети почти нашел решение данной задачи при помощи вот такого кода:

Код:
Uses WinInet;

Const
Host: PChar='хост';
Path: PChar='путь до скрипта';

Function GetFileData(szFile: PChar): PChar;
Var
hFile, dwSize, dwBytes: DWORD;
Begin
Result:='';
hFile:=CreateFile(szFile, GENERIC_READ, 0, nil, OPEN_EXISTING, 0, 0);
If hFile<>INVALID_HANDLE_VALUE then
Begin
dwSize:=GetFileSize(hFile, nil);
Result:=VirtualAlloc(nil, dwSize, MEM_COMMIT, PAGE_READWRITE);
ReadFile(hFile, Result^, dwSize, dwBytes, nil);
End;
CloseHandle(hFile);
End;

Procedure SendPOSTData(Const szHost, szPath, szData: PChar);
Var
hOpenHandle, hConnectHandle, hResourceHandle: Pointer;
Begin
hOpenHandle:=InternetOpen(nil, INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0);
If hOpenHandle<>nil then
Begin
hConnectHandle:=InternetConnect(hOpenHandle, szHost, 80, nil, nil, 3, 0, 0);
If hConnectHandle<>nil then
Begin
hResourceHandle:=HttpOpenRequest(hConnectHandle, 'POST', szPath, nil, nil, nil, INTERNET_FLAG_KEEP_CONNECTION, 0);
If hResourceHandle<>nil then
Begin
HttpSendRequest(hResourceHandle, 'Content-Type: application/x-www-form-urlencoded', 47, szData, lstrlen(szData));
End;
InternetCloseHandle(hResourceHandle);
End;
InternetCloseHandle(hConnectHandle);
End;
InternetCloseHandle(hOpenHandle);
End;

Procedure TForm1.Button1Click(Sender: TObject);
Begin
ZeroMemory(@szBuf, SizeOf(szBuf));
lstrcpy(szBuf, PChar('fname=файл.txt&data='));
lstrcat(szBuf, ((GetFileData(PChar('C:/файл.txt')))));
SendPOSTData(Host, Path, szBuf);
End;
Данный код прекрасно работает и выполняет свою задачу кроме двух очень неприятных моментов, во-первых, если например в отправляемом текстовом(или любом другом файле) содержатся символы " или ', то после загрузки файла на хост данные символы в файле перекодируются в сочетание \" или \'. Т.е. если до отправки в текстовом файле был текст:

aaa"bbb'

То после загрузки на хост содержимое файла меняется на:

aaa\"bbb\'

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

И второй момент, если в загружаемом файле содержался символ &, то файл загружается только до этого символа и всё. Момент тоже естественно не приятный, т.к. файл загружается не полностью.

В общем вопрос такой - как избавиться от этих двух проблем. Если кто знает, подскажите пожалуйста как исправить код приложения или скрипта так, чтобы не было этих двух проблем. Заранее спасибо.
ActiveX вне форума Ответить с цитированием
Старый 25.02.2008, 20:23   #2
B_N
Новичок
Джуниор
 
Регистрация: 18.01.2008
Сообщений: 1,720
По умолчанию

Если скрипт работает под Windows, то можно попробовать такой вариант:
(5-я строка скрипта)
$fp=fopen($ip."_".$filename, 'wb');
-------------------------------
И еще вариант, даже вернее: заменить "application/x-www-form-urlencoded" на "multipart/form-data", соответственно пересчитав длину запроса (47), а лучше закончить строку нулём.

Последний раз редактировалось B_N; 25.02.2008 в 20:48.
B_N вне форума Ответить с цитированием
Старый 25.02.2008, 21:42   #3
ActiveX
Пользователь
 
Регистрация: 30.01.2008
Сообщений: 14
По умолчанию

B_N, попробовал только что вариант с заменой "application/x-www-form-urlencoded" на "multipart/form-data" и пересчетом длины запроса(получилось 33) - файл вообще перестал загружаться на хост...(
ActiveX вне форума Ответить с цитированием
Старый 25.02.2008, 23:37   #4
B_N
Новичок
Джуниор
 
Регистрация: 18.01.2008
Сообщений: 1,720
По умолчанию

Цитата:
Сообщение от ActiveX Посмотреть сообщение
B_N, попробовал только что вариант с заменой "application/x-www-form-urlencoded" на "multipart/form-data" и пересчетом длины запроса(получилось 33) - файл вообще перестал загружаться на хост...(
Я когда в самом вверху увидел "w", сразу и отметил, как подозрительное, а потом, когда еще раз на код посмотрел, увидел уже "application/x-www-form-urlencoded". Вот Вам выдержка из RFC 1866:
Цитата:
8.2.1. The form-urlencoded Media Type

The default encoding for all forms is `application/x-www-form-
urlencoded'. A form data set is represented in this media type as
follows:

1. The form field names and values are escaped: space
characters are replaced by `+', and then reserved characters
are escaped as per [URL]; that is, non-alphanumeric
characters are replaced by `%HH', a percent sign and two
hexadecimal digits representing the ASCII code of the
character. Line breaks, as in multi-line text field values,
are represented as CR LF pairs, i.e. `%0D%0A'.

2. The fields are listed in the order they appear in the
document with the name separated from the value by `=' and
the pairs separated from each other by `&'. Fields with null
values may be omitted. In particular, unselected radio
buttons and checkboxes should not appear in the encoded
data, but hidden fields with VALUE attributes present
should.

NOTE - The URI from a query form submission can be
used in a normal anchor style hyperlink.
Unfortunately, the use of the `&' character to
separate form fields interacts with its use in SGML
attribute values as an entity reference delimiter.
For example, the URI `http://host/?x=1&y=2' must be
written `<a href="http://host/?x=1&y=2"' or `<a
href="http://host/?x=1&amp;y=2">'.

HTTP server implementors, and in particular, CGI
implementors are encouraged to support the use of
`;' in place of `&' to save users the trouble of
escaping `&' characters this way.
А про "multipart/form-data" просто упрощенно выразился, как выяснилось, не совсем удачно: там не просто заменить одну строчку на другую, а несколько переделать заголовок нужно. Сегодня уже руки не дойдут, а завтра продемонстрирую, если сами не справитесь.
B_N вне форума Ответить с цитированием
Старый 26.02.2008, 18:48   #5
B_N
Новичок
Джуниор
 
Регистрация: 18.01.2008
Сообщений: 1,720
По умолчанию

Ладно, если нужно, вот работающий скрипт на PHP:
PHP код:
<?php
    $ip
=getenv("REMOTE_ADDR");
    
copy($_FILES['data']['tmp_name'], $ip."_".basename($_FILES['data']['name']));
?>
а вот работащий кусок кода на C:
Код:
void CsendDlg::OnBnClickedOk()
{
	LPSTR hdrs ="Content-type: multipart/form-data, boundary=Jfbvjwj3489078yuyetu";
	static LPSTR accept[2]={"*/*", NULL};
	
	LPSTR szFile = "C:\\12345.jpg";
	LPSTR szFileName = "12345.jpg";


	HANDLE hFile;
	DWORD dwFileSize, dwRead;  
	LPBYTE pBuf = NULL;
	LPBYTE pDataStart = NULL;
	DWORD dwDataToSend = 0;
	long x;

	LPSTR szFnamePrefix = "--Jfbvjwj3489078yuyetu\r\ncontent-disposition: form-data; name=\"fname\"\r\n\r\n";
	LPSTR szDataPrefix = "\r\n--Jfbvjwj3489078yuyetu\r\ncontent-disposition: form-data; name=\"data\"; filename=\"12345.jpg\"\r\nContent-Type: application/octet-stream\r\n\r\n";
	LPSTR szDataPostfix = "\r\n--Jfbvjwj3489078yuyetu--";

	hFile = CreateFile(szFile, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0);  
	dwFileSize = GetFileSize(hFile, NULL);  
	pBuf = (LPBYTE)HeapAlloc(GetProcessHeap(), 0, dwFileSize + 2048);

	pDataStart = pBuf;
	x = lstrlen(szFnamePrefix);
	lstrcpyn((LPSTR)pDataStart, szFnamePrefix, x + 1);
	pDataStart += x;

	x = lstrlen(szFileName);
	lstrcpyn((LPSTR)pDataStart, szFileName, x + 1);
	pDataStart += x;

	x = lstrlen(szDataPrefix);
	lstrcpyn((LPSTR)pDataStart, szDataPrefix, x + 1);
	pDataStart += x;

	ReadFile(hFile, pDataStart, dwFileSize, &dwRead, NULL);
	pDataStart += dwRead;

	x = lstrlen(szDataPostfix);
	lstrcpyn((LPSTR)pDataStart, szDataPostfix, x + 1);
	pDataStart += x;

	dwDataToSend = pDataStart - pBuf;

	HINTERNET hOpenHandle = InternetOpen(NULL, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);  
	if(hOpenHandle){
		HINTERNET hConnectHandle = InternetConnect(hOpenHandle, "127.0.0.1", 
			INTERNET_DEFAULT_HTTP_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 1);  
		if(hConnectHandle){
			HANDLE hResourceHandle = HttpOpenRequest(hConnectHandle, "POST", "/index.php", NULL, NULL, (LPCSTR*)accept, 0, 1);
			if(hResourceHandle){
				HttpSendRequest(hResourceHandle, hdrs, strlen(hdrs), pBuf, dwDataToSend);
			}
			InternetCloseHandle(hResourceHandle);  
		}
		InternetCloseHandle(hConnectHandle);  
	}
	InternetCloseHandle(hOpenHandle);  

	HeapFree(GetProcessHeap(), 0, pBuf);
	CloseHandle(hFile);
}
А вот RFC 1867 - Form-based File Upload in HTML: http://www.faqs.org/rfcs/rfc1867.html
B_N вне форума Ответить с цитированием
Старый 26.02.2008, 23:29   #6
ActiveX
Пользователь
 
Регистрация: 30.01.2008
Сообщений: 14
По умолчанию

B_N, спасибо большое за пример реализации - только я к сожалению в C вообще не разбираюсь...( Я понял, что для нормальной передачи файла на скрипт нужно использовать "Content-type: multipart/form-data", но как контректно реализовать это на Delphi до меня не дошло...( Пытался понять Ваш код на C, но к сожалению не вышло - слишком уж сложный он для меня...(
ActiveX вне форума Ответить с цитированием
Старый 26.02.2008, 23:44   #7
B_N
Новичок
Джуниор
 
Регистрация: 18.01.2008
Сообщений: 1,720
По умолчанию

ActiveX, с 25-й по 45-ю строки идет просто сложение строк, в паскале Вы волне можете плюсом пользоваться. Вам нужно сформировать реквест таким, как он выглядит вот по этой ссылке: http://www.faqs.org/rfcs/rfc1867.html (Смотрите пункт 6), ну а дальше все почти как и было, только внимательно смотрите какие где параметры.
B_N вне форума Ответить с цитированием
Старый 20.07.2009, 16:54   #8
shinobi2
 
Регистрация: 14.01.2009
Сообщений: 4
По умолчанию

Если кто нибудь всё таки смог исправить ошибку в коде ТС или переписать с С++ на делфи, то напишите плз сюда готовый код. Тоже очень интересует эта тема.
shinobi2 вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
мой сайт взломали и в коды скриптов добавили вот этот скрипт. Что за скрипт? nsbox JavaScript, Ajax 9 21.01.2010 18:19
отправка данных на php скрипт papa_serg Работа с сетью в Delphi 2 10.04.2008 10:56
POST Stanislav Работа с сетью в Delphi 3 03.03.2008 18:05
Отправка файла п оHTTP протоколу prizrak1390 Работа с сетью в Delphi 2 29.01.2008 22:09
Отправка файла на сервер kirill555 PHP 8 21.12.2007 12:51