Search code examples
phpdelphipostcharacter-encodingindy

Delphi Indy Post Encoding and PHP


The string returned from php script is encoded.

I have a problem with an http post in delphi 2007 and Indy 10.6 towards a php script. The php script contains: header ("Content-Type: application / json; charset = UTF-8"); The Delphi part is this:

  data: = TStringList.Create;

  dati.Values ​​['id']: = '6';
  dati.Values ​​['name']: = 'àèìòù';

  lParams: = TIdMultiPartFormDataStream.Create;
  cont: = 0;
  try
    try
      url: = 'someurl';
      while cont <= data.Count-1 do
      begin
        lParams.AddFormField (data.Names [cont], data.Values ​​[data.Names [cont]]);
        Inc (cont);
      end;
      Response: = IdHTTP1.Post (url, lParams);
    except
      on E: Exception do
      Response: = E.ClassName + ':' + E.Message;
    end;
  finally
    lParams.Free;
    IdHTTP1.Disconnect;
  end;
  Result: = Response;

Response contains what should be saved in the mysql database whose varchar field is declared utf8-general-i both in the field and in the php echo, however, they return: = E0 = E8 = EC = F2 = F9

I tried to encode with UTF8Encode (dati.Values ​​[data.Names [cont]]), I tried to pass the UTF-8 charset to AddFormField but the string àèìòù is never returned.

What am I doing wrong?


Solution

  • What you have shown looks like MIME's quoted-printable encoding, where non-ASCII/reserved byte octets are encoded in =HH hex format. TIdMultiPartFormDataStream does encode text fields in quoted-printable format by default. =E0=E8=EC=F2=F9 is the QP-encoded form of the byte sequence $E0 $E8 $EC $F2 $F9, which is the text 'àèìòù' encoded in the Latin-1 (ISO-8859-1) charset.

    PHP does not support the Content-Transfer-Encoding header in multipart/form-data submissions (see this), so it does not automatically decode the QP encoding for you. So, you will have to either:

    • decode the QP encoding manually in your PHP script code.

    • disable TIdMultipartFormDataStream from applying QP encoding, by setting the TIdFormDataField.ContentTransfer property to '8bit' instead of the default 'quoted-printable' (note that RFC 7578 deprecates the use of the Content-Transfer-Encoding header in multipart/form-data submissions over HTTP, but TIdMultipartFormDataStream has not been updated to account for that yet 1).

      1: Note - the TIdFormDataField.ContentTransfer property can be set to a blank string, which will disable the Content-Transfer-Encoding header from being sent, but it will also send the text as 7-bit US-ASCII, per RFC 2045 Section 6.1, so don't use this option if you need to send text that contains non-ASCII characters.

    Also, be aware that Delphi 2007 is not a Unicode enabled version of Delphi (ie, String = AnsiString), which is why your text is being posted in Latin-1. In pre-Unicode versions, TIdMultiPartFormDataStream transmits AnsiString data as-is, so you are responsible for pre-encoding the posted AnsiStrings in the desired byte encoding, such as UTF-8.

    Try this instead:

    url := 'someurl';
    
    try
      data := TStringList.Create;
      try
        data.Values ​​['id']: = '6';
        data.Values ​​['name'] := UTF8Encode('àèìòù'); // <-- omit UTF8Encode() in D2009+...
    
        lParams := TIdMultiPartFormDataStream.Create;
        try
          for cont := 0 to data.Count-1 do
          begin
            lParams.AddFormField(data.Names[cont], data.ValueFromIndex[cont], 'utf-8').ContentTransfer := '8bit';
          end;
    
          try
            Response := IdHTTP1.Post(url, lParams);
          finally
            IdHTTP1.Disconnect;
          end;
        finally
          lParams.Free;
        end;
      finally
        data.Free;
      end;
    except
      on E: Exception do
        Response := E.ClassName + ':' + E.Message;
    end;
    
    Result := Response;