2016-11-19 22 views
-1

У меня возникла ситуация с TIdHTTP и TIdMultipartFormDataStream.Ошибка кодирования символов в idHTTP

Мой код:

FormPHP := TIdMultiPartFormDataStream.Create; 
    FormPHP.AddFile('imagem',AImagem,'image/jpeg'); 
    FormPHP.AddFormField('iduser',AIDUser,'text/plain'); 
    FormPHP.AddFormField('nome',ANome,'text/plain'); 
    FormPHP.AddFormField('data',AData,'text/plain'); 
    FormPHP.AddFormField('hora',AHora,'text/plain'); 
    FormPHP.AddFormField('mensagem',AMensagem,'text/plain'); 
    FormPHP.AddFormField('latitude','1','text/plain'); 
    FormPHP.AddFormField('longitude','1','text/plain'); 

    Response := TStringStream.Create('', TEncoding.ANSI); 

    HTTP:= TIdHTTP.Create(self); 
    HTTP.Request.CustomHeaders.Clear; 
    HTTP.Request.Clear; 
    HTTP.Request.ContentType:= 'multipart/form-data'; //application/x-www-form-urlencoded 
    HTTP.Request.ContentEncoding:= 'MeMIME'; 
    HTTP.Request.CharSet:= 'utf-8'; 
    HTTP.Request.Referer:= 'http://observadordecascavel.blog.br/cadastro.php'; 
    HTTP.Post('http://observadordecascavel.blog.br/cadastro.php',FormPHP,Response); 

Это PHP скрипт:

<?php 
    #cadastro.php - Cadastra os dados enviados na tabela online. 
    $mysqli = new mysqli("mysqlhost","username","password","dbname"); 

    $iduser   = $_POST['iduser']; 
    $nome   = $_POST['nome']; 
    $data   = $_POST['data']; 
    $hora   = $_POST['hora']; 
    $mensagem  = $_POST['mensagem']; 
    $latitude  = $_POST['latitude']; 
    $longitude  = $_POST['longitude']; 
    $imagem   = $_FILES["imagem"]['tmp_name']; 
    $tamanho  = $_FILES['imagem']['size']; 

    if ($imagem != "none") 
    { 
     $fp = fopen($imagem, "rb"); 
     $conteudo = fread($fp, $tamanho); 
     $conteudo = addslashes($conteudo); 
     fclose($fp); 

     $queryInsercao = "INSERT INTO tabpainel (iduser, nome, data, hora, mensagem, latitude, longitude, imagem) VALUES ('$iduser', '$nome', '$data','$hora','$mensagem', '$latitude', '$longitude', '$conteudo')"; 

     mysqli_query($mysqli,$queryInsercao) or die("Algo deu errado ao inserir o registro. Tente novamente."); 

     if(mysqli_affected_rows($mysqli) > 0) 
      print "Sucesso!"; 
     else 
      print "Não foi possível inserir o registro"; 
    } 
    else 
     print "Não á foi possível carregar a imagem."; 
    ?> 

Разъяснение: Мое приложение после этих полей в этом PHP скрипт и PHP сохраняет данные в базу данных MySQL и возвращает ответ «Sucesso!» в приложение, чтобы сообщить пользователю, что данные были сохранены. Этот текстовый ответ закодирован в ANSI. Я обнаружил, что когда мне пришлось сменить кодировку TStringStream на TEncoding.ANSI, она могла распознать слово «Não», когда что-то пойдет не так.

До постов переменная AMensagem в порядке, однако, когда PHP получает текст, это неверно. Текст, подобный этому: «á Á é É» выглядит следующим образом: «= E1 = C1 = E9 = C9». Это сохраняется в базе данных mysql.

Я не знаю, связана ли проблема с idHTTP или с TIdMultipartFormDataStream или даже с кодом PHP. Все работает нормально, это просто кодировка, что я не знаю, почему она не работает.

ответ

1

Текст, передаваемый на сервер, не кодируется в UTF-8.

Все ваши AddFormField() вызовов с указанием типа text/plain носителя в параметре ACharset вместо параметра AContentType. В отличие от AddFile(), третий параметр AddFormField() - это кодировка, а 4-й параметр - тип носителя.

function AddFormField(const AFieldName, AFieldValue: string; const ACharset: string = ''; const AContentType: string = ''; const AFileName: string = ''): TIdFormDataField; overload; 

Передавая неверный набор символов, TIdMultipartFormDataStream заканчивает с помощью встроенного в сыром 8bit кодирование Инди вместо, который кодирует символы Unicode U+0000 - U+00FF как байты $00 - $FF, соответственно, и все другие символы как байты $3F ('?'). Текст, который вы отправляете , происходит, чтобы попасть в этот первый диапазон.

TIdFormDataField в настоящее время не наследует кодировку из TIdMultipartFormDataStream или TIdHTTP (работы на том, что находится в стадии разработки), так что вы должны указать его на основе каждого поля.

На боковой ноте MeMIME недействительно ContentEncoding. И в любом случае вы не должны устанавливать значение ContentEncoding для сообщения multipart/form-data.

Попробуйте что-то больше, как это вместо:

FormPHP := TIdMultiPartFormDataStream.Create; 

FormPHP.AddFile('imagem', AImagem, 'image/jpeg'); 
FormPHP.AddFormField('iduser', AIDUser, 'utf-8'); 
FormPHP.AddFormField('nome', ANome, 'utf-8'); 
FormPHP.AddFormField('data', AData, 'utf-8'); 
FormPHP.AddFormField('hora', AHora, 'utf-8'); 
FormPHP.AddFormField('mensagem', AMensagem, 'utf-8'); 
FormPHP.AddFormField('latitude', '1'); 
FormPHP.AddFormField('longitude', '1'); 

Response := TStringStream.Create(''); 

HTTP := TIdHTTP.Create(Self); 
HTTP.Request.Referer := 'http://observadordecascavel.blog.br/cadastro.php'; 
HTTP.Post('http://observadordecascavel.blog.br/cadastro.php', FormPHP, Response); 

В качестве альтернативы:

FormPHP := TIdMultiPartFormDataStream.Create; 

FormPHP.AddFile('imagem', AImagem, 'image/jpeg'); 
FormPHP.AddFormField('iduser', AIDUser).Charset := 'utf-8'; 
FormPHP.AddFormField('nome', ANome).Charset := 'utf-8'; 
FormPHP.AddFormField('data', AData).Charset := 'utf-8'; 
FormPHP.AddFormField('hora', AHora).Charset := 'utf-8'; 
FormPHP.AddFormField('mensagem', AMensagem).Charset := 'utf-8'; 
FormPHP.AddFormField('latitude', '1'); 
FormPHP.AddFormField('longitude', '1'); 

Response := TStringStream.Create(''); 

HTTP := TIdHTTP.Create(Self); 
HTTP.Request.Referer := 'http://observadordecascavel.blog.br/cadastro.php'; 
HTTP.Post('http://observadordecascavel.blog.br/cadastro.php', FormPHP, Response); 

В любом случае, текстовое поле будет кодируются с использованием UTF-8 вместо Анси.


Update: Теперь, с тем, что, AddFormField() устанавливает TIdFormDataField.ContentTransfer свойство quoted-printable по умолчанию.Однако РНР $_POST не декодирует quoted-printable по умолчанию, вы должны вызвать quoted_printable_decode() вручную:

$iduser   = quoted_printable_decode($_POST['iduser']); 
$nome   = quoted_printable_decode($_POST['nome']); 
$data   = quoted_printable_decode($_POST['data']); 
$hora   = quoted_printable_decode($_POST['hora']); 
$mensagem  = quoted_printable_decode($_POST['mensagem']); 
$latitude  = quoted_printable_decode($_POST['latitude']); 
$longitude  = quoted_printable_decode($_POST['longitude']); 

Если вы не хотите TIdFormDataField для кодирования текста UTF-8 с помощью quoted-printable, вы можете установить ContentTransfer свойство 8bit вместо того, чтобы:

FormPHP.AddFormField('iduser', AIDUser, 'utf-8').ContentTransfer := '8bit'; 
FormPHP.AddFormField('nome', ANome, 'utf-8').ContentTransfer := '8bit'; 
FormPHP.AddFormField('data', AData, 'utf-8').ContentTransfer := '8bit'; 
FormPHP.AddFormField('hora', AHora, 'utf-8').ContentTransfer := '8bit'; 
FormPHP.AddFormField('mensagem', AMensagem, 'utf-8').ContentTransfer := '8bit'; 
FormPHP.AddFormField('latitude', '1'); 
FormPHP.AddFormField('longitude', '1'); 

В качестве альтернативы:

with FormPHP.AddFormField('iduser', AIDUser) do begin 
    Charset := 'utf-8'; 
    ContentTransfer := '8bit'; 
end; 
with FormPHP.AddFormField('nome', ANome) do begin 
    Charset := 'utf-8'; 
    ContentTransfer := '8bit'; 
end; 
with FormPHP.AddFormField('data', AData) do begin 
    Charset := 'utf-8'; 
    ContentTransfer := '8bit'; 
end; 
with FormPHP.AddFormField('hora', AHora) do begin 
    Charset := 'utf-8'; 
    ContentTransfer := '8bit'; 
end; 
with FormPHP.AddFormField('mensagem', AMensagem) do begin 
    Charset := 'utf-8'; 
    ContentTransfer := '8bit'; 
end; 
FormPHP.AddFormField('latitude', '1'); 
FormPHP.AddFormField('longitude', '1'); 

В любом случае, вы можете использовать исходный код PHP снова:

$iduser   = $_POST['iduser']; 
$nome   = $_POST['nome']; 
$data   = $_POST['data']; 
$hora   = $_POST['hora']; 
$mensagem  = $_POST['mensagem']; 
$latitude  = $_POST['latitude']; 
$longitude  = $_POST['longitude']; 

Используете ли вы quoted-printable или нет, PHP переменные будут в конечном итоге проведение UTF-8, закодированный текст. Если вам нужны переменные, чтобы быть в другом кодировании, вы должны преобразовать их по мере необходимости, используя либо:

  1. utf8_decode() (который декодирует с ISO-8859-1):

    $iduser   = utf8_decode($iduser); 
    $nome   = utf8_decode($nome); 
    $data   = utf8_decode($data); 
    $hora   = utf8_decode($hora); 
    $mensagem  = utf8_decode($mensagem); 
    $latitude  = utf8_decode($latitude); 
    $longitude  = utf8_decode($longitude); 
    
  2. mb_convert_encoding()

    $iduser   = mb_convert_encoding($iduser, 'desired charset', 'utf-8'); 
    $nome   = mb_convert_encoding($nome), 'desired charset', 'utf-8'); 
    $data   = mb_convert_encoding($data, 'desired charset', 'utf-8'); 
    $hora   = mb_convert_encoding($hora, 'desired charset', 'utf-8'); 
    $mensagem  = mb_convert_encoding($mensagem, 'desired charset', 'utf-8'); 
    $latitude  = mb_convert_encoding($latitude, 'desired charset', 'utf-8'); 
    $longitude  = mb_convert_encoding($longitude, 'desired charset', 'utf-8'); 
    
  3. iconv():

    $iduser   = iconv('utf-8', 'desired charset', $iduser); 
    $nome   = iconv('utf-8', 'desired charset', $nome); 
    $data   = iconv('utf-8', 'desired charset', $data); 
    $hora   = iconv('utf-8', 'desired charset', $hora); 
    $mensagem  = iconv('utf-8', 'desired charset', $mensagem); 
    $latitude  = iconv('utf-8', 'desired charset', $latitude); 
    $longitude  = iconv('utf-8', 'desired charset', $longitude); 
    

Наконец, при отправке ответа клиенту необходимо кодировать текст, когда он содержит символы, отличные от ASCII. Вы также должны использовать header(), чтобы позволить клиенту знать, какая кодировка используется для этой кодировки:

header($_SERVER["SERVER_PROTOCOL"] . " 200 OK"); 
header('Content-Type: text/plain; charset="utf-8"'); 

if ($imagem != "none") 
{ 
    ... 
    if (mysqli_affected_rows($mysqli) > 0) 
     print utf8_encode("Sucesso!"); 
    else 
     print utf8_encode("Não foi possível inserir o registro"); 
} 
else 
    print utf8_encode("Não á foi possível carregar a imagem."); 
+0

Изменения, сделанные, но проблема все еще существует. – wordermorr

+0

@wordermorr, какие версии Delphi и Indy вы используете? –

+0

Delphi Seattle and Indy 10.6.2.5298 – wordermorr