0

I found this script How to send a HTTP POST Request in Delphi using WinInet api

but in Delphi Xe6 doesn't run correctly

My XE6 code is

procedure TForm2.WebPostData(const UserAgent: WideString; const Server: string; const Resource: WideString; const Data: WideString);
var
  hInet: HINTERNET;
  hHTTP: HINTERNET;
  hReq: HINTERNET;
  pRequest: HINTERNET;

  Buffer: array[0..1023] of AnsiChar;
  i, BufferLen: cardinal;
  Res: string;

  Heade      : TStringStream;
  BufStream   : TMemoryStream;
  aBuffer     : Array[0..4096] of Char;
  BytesRead   : Cardinal;
resu : AnsiString;
const
//  post: packed array[0..4] of LPWSTR = (PWideChar('POST'), nil);
  accept: packed array[0..1] of LPWSTR = (PChar('*/*'), nil);
//  header: string = 'Content-Type: application/x-www-form-urlencoded;charset=utf-8';
  header: string = 'Content-Type: application/x-www-form-urlencoded';
begin
  hInet := InternetOpen(PChar(UserAgent), INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0);
  try
    hHTTP := InternetConnect(hInet, PChar(Server), INTERNET_DEFAULT_HTTP_PORT, nil, nil, INTERNET_SERVICE_HTTP, 0, 1);
    try
      hReq := HttpOpenRequest(hHTTP, PWideChar('POST'), PWideChar(Resource), nil, nil, @accept, 0, 1);
//      hReq := HttpOpenRequest(hHTTP, @post, PWideChar(Resource), nil, nil, @accept, 0, 1);





{
      pRequest := hReq;
      if Assigned(pRequest) then
      try
        Heade := TStringStream.Create('');
        try
          with Heade do
          begin
            WriteString('Host: ' + 'www.site.com' + sLineBreak);
            WriteString('User-Agent: Custom program 1.0'+SLineBreak);
            WriteString('Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'+SLineBreak);
            WriteString('Accept-Language: en-us,en;q=0.5' + SLineBreak);
            WriteString('Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7'+SLineBreak);
            WriteString('Keep-Alive: 300'+ SLineBreak);
            WriteString('Connection: keep-alive'+ SlineBreak+SLineBreak);
          end;

          HttpAddRequestHeaders(pRequest, PChar(Heade.DataString), Length(Heade.DataString), HTTP_ADDREQ_FLAG_ADD);

          if HTTPSendRequest(pRequest, nil, 0, Pointer(Data), Length(Data)) then
          begin
            BufStream := TMemoryStream.Create;
            try
              while InternetReadFile(pRequest, @aBuffer, SizeOf(aBuffer), BytesRead) do
              begin
                if (BytesRead = 0) then Break;
                BufStream.Write(aBuffer, BytesRead);
              end;

              aBuffer[0] := #0;
              BufStream.Write(aBuffer, 1);
              Resu := PChar(BufStream.Memory);
              ShowMessage(Resu);
            finally
              BufStream.Free;
            end;
          end;
        finally
          Heade.Free;
        end;
      finally
        InternetCloseHandle(pRequest);
      end;
}











      try
//        if not HttpSendRequest(hReq, System.PWideChar(header), Length(System.PWideChar(header)), PWideChar(Data), length(Data)) then begin
          if not HTTPSendRequest(hReq, nil, 0, Pointer(Data), Length(Data)) then begin
          ShowMessage('HttpOpenRequest failed. ' + SysErrorMessage(GetLastError));
        end else begin

          repeat
            InternetReadFile(hReq, @Buffer, SizeOf(Buffer), BufferLen);
            if BufferLen = SizeOf(Buffer) then
              Res := Res + AnsiString(Buffer)
            else if BufferLen > 0 then
              for i := 0 to BufferLen - 1 do
                Res := Res + Buffer[i];
          until BufferLen = 0;
ShowMessage(Res);
        end;
      finally
        InternetCloseHandle(hReq);
      end;
    finally
      InternetCloseHandle(hHTTP);
    end;
  finally
    InternetCloseHandle(hInet);
  end;
end;

my php code is

echo 'metodo ' . $_SERVER['REQUEST_METHOD'];
$post = file_get_contents('php://input');
print_r($post);
print_r($_GET['value']);
print_r($_POST['value']);
print_r($_REQUEST['value']);
?>
bye

but php tell me that method is GET In fact, I can not read the variable $ _POST

Community
  • 1
  • 1
Janka
  • 1,908
  • 5
  • 20
  • 41

1 Answers1

1

You have some errors in your code. Most notably, you are mixing string types, and you are transmitting your Data parameter as-is in its original UTF-16 format, which the server is not expecting since you are not sending a charset=utf-16 value in the request's Content-Type header. You need to ensure the Data is in the correct format before you can send it.

Try something more like this instead:

procedure TForm2.WebPostFormData(const UserAgent: String; const Server: string; const Resource: String; const Data: TStrings);
var
  FormData: TStringList;
  PostData: UTF8String;
  I: Integer;
  BufStream: TMemoryStream;
  Resu: AnsiString;
begin
  FormData := TStringList.Create;
  try
    FormData.NameValueSeparator := '=';
    FormData.LineBreak := '&';
    for I := 0 to Data.Count-1 do
    begin
      // TODO: URL-encode the name and value...
      FormData.Add(Data.Names[I] + '=' + Data.ValueFromIndex[I]);
    end;
    PostData := UTF8String(FormData.Text);
  finally
    FormData.Free;
  end;

  BufStream := TMemoryStream.Create;
  try
    WebPostData(UserAgent, Server, Resource, PAnsiChar(PostData), Length(PostData), 'application/x-www-form-urlencoded; charset="utf-8"', BufStream);
    SetString(Resu, PAnsiChar(BufStream.Memory), BufStream.Size);
  finally
    BufStream.Free;
  end;

  ShowMessage(String(Resu));
end;

procedure TForm2.WebPostData(const UserAgent: String; const Server: string; const Resource: String; const Data: Pointer; DataSize: UInt32; const ContentType: String; Response: TStream);
var
  hInet: HINTERNET;
  hHTTP: HINTERNET;
  hReq: HINTERNET;    
  Heade: String;
  Buffer: array[0..1023] of Byte;
  BytesRead: DWORD;
const
  accept: packed array[0..1] of PChar = (PChar('*/*'), nil);
begin
  hInet := InternetOpen(PChar(UserAgent), INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0);
  if hInet = 0 then RaiseLastOSError;
  try
    hHTTP := InternetConnect(hInet, PChar(Server), INTERNET_DEFAULT_HTTP_PORT, nil, nil, INTERNET_SERVICE_HTTP, 0, 1);
    if hHTTP = 0 then RaiseLastOSError;
    try
      hReq := HttpOpenRequest(hHTTP, PChar('POST'), PChar(Resource), nil, nil, @accept, INTERNET_FLAG_KEEP_CONNECTION, 1);
      if hReq = 0 then RaiseLastOSError;
      try
        Heade := 'User-Agent: ' + UserAgent + #13#10 +
                 'Accept-Language: en-us,en;q=0.5'#13#10 +
                 'Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7'#13#10 +
                 'Content-Type: ' + ContentType + #13#10 +
                 'Keep-Alive: 300'#13#10;

        if not HttpAddRequestHeaders(hReq, PChar(Heade), Length(Heade), HTTP_ADDREQ_FLAG_ADD) then RaiseLastOSError;

        if not HTTPSendRequest(hReq, nil, 0, Data, DataSize) then RaiseLastOSError;

        repeat
          if not InternetReadFile(hReq, @Buffer, SizeOf(Buffer), BytesRead) then RaiseLastOSError;
          if (BytesRead = 0) then Break;
          if Response <> nil then
            Response.WriteBuffer(Buffer, BytesRead);
        until False;
      finally
        InternetCloseHandle(hReq);
      end;
    finally
      InternetCloseHandle(hHTTP);
    end;
  finally
    InternetCloseHandle(hInet);
  end;
end;

Alternatively, consider switching to Indy's TIdHTTP component and let it do the work for you:

uses
  ..., IdGlobal, IdHTTP;

procedure TForm2.WebPostFormData(const UserAgent: String; const Server: string; const Resource: String; const Data: TStrings);
var
  HTTP: TIdHTTP;
  Resu: String;
begin
  HTTP := TIdHTTP.Create(nil);
  try
    HTTP.Request.Accept := '*/*';
    HTTP.Request.UserAgent := UserAgent;
    HTTP.Request.AcceptLanguage := 'en-us,en;q=0.5';
    HTTP.Request.AcceptCharset := 'ISO-8859-1,utf-8;q=0.7,*;q=0.7';
    HTTP.Request.ContentType := 'application/x-www-form-urlencoded';
    HTTP.Request.Charset := 'utf-8';
    HTTP.Request.Connection := 'keep-alive';
    HTTP.Request.CustomHeaders.Values['Keep-Alive'] := '300';

    Resu := HTTP.Post('http://' + Server + Resource, Data);
  finally
    HTTP.Free;
  end;

  ShowMessage(Resu);
end;

procedure TForm2.WebPostData(const UserAgent: String; const Server: string; const Resource: String; const Data: Pointer; DataSize: UInt32; const ContentType: String; Response: TStream);
var
  HTTP: TIdHTTP;
  DataStrm: TIdMemoryBufferStream;
begin
  HTTP := TIdHTTP.Create(nil);
  try
    HTTP.Request.Accept := '*/*';
    HTTP.Request.UserAgent := UserAgent;
    HTTP.Request.AcceptLanguage := 'en-us,en;q=0.5';
    HTTP.Request.AcceptCharset := 'ISO-8859-1,utf-8;q=0.7,*;q=0.7';
    HTTP.Request.ContentType := ContentType;
    HTTP.Request.Connection := 'keep-alive';
    HTTP.Request.CustomHeaders.Values['Keep-Alive'] := '300';

    DataStrm := TIdMemoryBufferStream.Create(Data, DataSize);
    try
      HTTP.Post('http://' + Server + Resource, DataStrm, Response);
    finally
      DataStrm.Free;
    end;
  finally
    HTTP.Free;
  end;
end;
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • No the code doesn't run. PHP return metod GET. It's possible configure TIdHTTP for use the user internet configuration? – Janka Jan 18 '17 at 12:05
  • @Janka considering that `HttpOpenRequest()` specifically says POST, the only way the server could be seeing GET is if either the server redirects the client to change methods, or the connection is passing through a proxy that changes the method. What does PHP say the complete request looks like? Are you sure you are looking at the correct request to begin with? – Remy Lebeau Jan 18 '17 at 18:01