Ошибка кодировки символов в idHTTP

У меня возникла ситуация с TIdHTTP и TIdMultipartFormDataStream.

Мой код:

  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()3-й параметр AddFormField() является кодировкой, а 4-й параметр является типом носителя.

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

Передавая неверный набор символов, TIdMultipartFormDataStream заканчивает тем, что вместо этого использует встроенную 8-битную кодировку Indy, которая кодирует символы 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 вместо Ansi.


ОбновитьТеперь, с этим сказал, AddFormField() устанавливает TIdFormDataField.ContentTransfer собственность на quoted-printable по умолчанию. Тем не менее, PHP $_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.");
1

Другие решения

Других решений пока нет …

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector