Форум программистов
 
Контакты: о проблемах с регистрацией, почтой и по другим вопросам пишите сюда - alarforum@yandex.ru, проверяйте папку спам! Обязательно пройдите активизацию e-mail.

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

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

Ответ
 
Опции темы
Старый 25.02.2008, 21:03   #1
ActiveX
Пользователь
 
Регистрация: 31.01.2008
Сообщений: 14
Репутация: 10
По умолчанию Отправка файла 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, 21:23   #2
B_N
Новичок
 
Регистрация: 18.01.2008
Сообщений: 1,720
Репутация: 590
По умолчанию

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

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

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

Цитата:
Сообщение от 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, 19:48   #5
B_N
Новичок
 
Регистрация: 18.01.2008
Сообщений: 1,720
Репутация: 590
По умолчанию

Ладно, если нужно, вот работающий скрипт на 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 вне форума   Ответить с цитированием
Старый 27.02.2008, 00:29   #6
ActiveX
Пользователь
 
Регистрация: 31.01.2008
Сообщений: 14
Репутация: 10
По умолчанию

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

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

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

Опции темы

Ваши права в разделе
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.

Быстрый переход

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


16:19.


Powered by vBulletin® Version 3.8.8 Beta 2
Copyright ©2000 - 2018, Jelsoft Enterprises Ltd.

RusProfile.ru


Справочник российских юридических лиц и организаций.
Проекты отопления, пеллетные котлы, бойлеры, радиаторы
интернет магазин respective.ru