Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: Сети > Логин по IdHTTP на php сервер


Автор: chekist 19.6.2007, 10:38
Вопрос такой: нужно залогиниться с помощью delphi (idHTTP) на сервер (php) и загрузить ряд страниц.

Сервер: http://vkontakte.ru

Делаю так:

Код


var
  str:TStringList;
begin

  str:=TStringList.Create;
  str.Add('[email protected]');
  str.Add('pass=yyy');

  // попытка логина
  RichEdit1.Lines.Add(IdHTTP1.Post('http://vkontakte.ru/login.php',str));
  RichEdit1.Lines.Add(IdHTTP1.Response.Location);
  RichEdit1.Lines.Add(IdHTTP1.Response.ResponseText);

  // попытка получить страницу
  RichEdit1.Lines.Add(IdHTTP1.Get('profile.php'));

  str.Free;
end;



После запроса Post выдает  HTTP/1.1 302 Found    и предлагает перейти на страницу  profile.php . Вроде так и должно быть.
Но когда пытаюсь получить страницу, пишет:  Чтобы просматривать эту страницу, нужно зайти на сайт .

CookieManager прикрутил стандартным способом, через компоненты.

Нашел на форуме тему с подобной проблемой:  http://forum.vingrad.ru/topic-81091.html
Там проблемы разрешились. Вроде делаю все так же, но проблемы остаются.

Спасибо.  

Автор: Snowy 19.6.2007, 10:58
Включи HandleRedirects - он сам перейдёт, куда нужно.
Также посмотри сниффером или маппером, что шлёт браузер, а что ты.

Автор: chekist 19.6.2007, 17:19
Посмотрел маппером. Кажется у меня что-то странное творится с Cookie.

В ответ на запрос POST, как и ожидалось,  приходит ответ с Cookie.
Однако в следующем запросе GET Indy никаких Cookie не вставляет (в отличие от браузера).

Может я как-то неправильно подключил/настроил CookieManager ?

Автор: aktuba 19.6.2007, 18:35
Цитата

Может я как-то неправильно подключил/настроил CookieManager ? 


А ты прописал его в IdHTTP?

Автор: chekist 19.6.2007, 18:52
aktuba
Я кинул на форму компонент IdCookieManager, добавил его через инспектор в 
свойстве CookieManager у компонента IdHTTP и выставил AllowCookies в true.


Автор: Snowy 19.6.2007, 19:42
chekist, в IdHttp менеджер куков нужно указать.
Свойство CookieManager IdHTTP - выбери его. Иначе он просто валяться будет, но никак не работать...

Автор: chekist 19.6.2007, 20:25
Snowy
Цитата

в IdHttp менеджер куков нужно указать.
Свойство CookieManager IdHTTP - выбери его. Иначе он просто валяться будет, но никак не работать...


Чего-то я не совсем понял. А я что по-твоему сделал?

Автор: aktuba 19.6.2007, 20:25
chekist, выложи проект тестовый - посмотрим. Так трудно сказать.

Автор: chekist 19.6.2007, 20:41
Цитата

chekist, выложи проект тестовый - посмотрим. Так трудно сказать.


O.K. Вот проект.

Я надеюсь те, кто будет мне помогать, зарегистрированы в контакте, чтобы его потестировать.

Автор: aktuba 20.6.2007, 03:53
chekist, за такую задачку я бы тебе поставил плюс, но думаю рановато для тебя =)

Итак. Задачка действительно оказалась интересной и, не скрою, я ее не до конца еще решил... Надо будет покопаться поглубже, для того чтобы найти красивое решение. Но если в кратце, то проблема в следующем. Вот так выглядит установка куков для этого сайта:
Код

Set-Cookie: remixchk=2; expires=Thu, 19-Jun-2008 00:55:33 GMT; path=/; domain=.vkontakte.ru
Set-Cookie: remixmid=23452; expires=Thu, 19-Jun-2008 00:55:33 GMT; path=/; domain=.vkontakte.ru
Set-Cookie: remixemail=aktuba%40yandex.ru; expires=Thu, 19-Jun-2008 00:55:33 GMT; path=/; domain=.vkontakte.ru
Set-Cookie: remixpass=52120febf525e8abeb9c95e9dce2c930; expires=Thu, 19-Jun-2008 00:55:33 GMT; path=/; domain=.vkontakte.ru


Вся проблема кроется в том, что в куках прописано на какой домен ставить эту куку: path=/; domain=.vkontakte.ru
Браузеры такое глотают легко, просто отбрасывая точку впереди, а вот Indy на этом валиться по следующей причине:

Код

  ACookie.CookieText := ACookieText;

  if Length(ACookie.Domain) = 0 then LDomain := AHost
  else LDomain := ACookie.Domain;

  ACookie.Domain := LDomain;

  if ACookie.IsValidCookie(AHost) then
  begin
    if DoOnNewCookie(ACookie) then
    begin
      FCookieCollection.AddCookie(ACookie);
    end
    else begin
      ACookie.Collection := nil;
      ACookie.Free;
    end;
  end
  else begin
    ACookie.Free;
  end;


Тут видно, что именно для .vkontakte.ru будут ставиться куки, а не для vkontakte.ru. Если покопаться дальше, то можно найти вот такие сравнения:
Код

Result := ((IndyPos('.', S) = 0) or (S[1] <> '.')) and NOT IsValidIP(S);


Как не трудно понять - эти сравнения всегда будут давать False, если домен, для которого устанавливается кука, впереди содержит точку. Вот и вся проблема =)))) Решение, на данный момент, простое. В модуль IdCookieManager, в процедуру DoAdd надо добавить одну строку:
Код

if LDomain[1] = '.' then LDomain := Copy(LDomain, 2, Length(LDomain) - 1);


Теперь эта процедура будет выглядеть так:
Код

procedure TIdCookieManager.DoAdd(ACookie: TIdCookieRFC2109; ACookieText, AHost: String);
Var
  LDomain: String;
begin
  ACookie.CookieText := ACookieText;

  if Length(ACookie.Domain) = 0 then LDomain := AHost
  else LDomain := ACookie.Domain;

  if LDomain[1] = '.' then LDomain := Copy(LDomain, 2, Length(LDomain) - 1);
  ACookie.Domain := LDomain;

  if ACookie.IsValidCookie(AHost) then
  begin
    if DoOnNewCookie(ACookie) then
    begin
      FCookieCollection.AddCookie(ACookie);
    end
    else begin
      ACookie.Collection := nil;
      ACookie.Free;
    end;
  end
  else begin
    ACookie.Free;
  end;
end;


После этого все работает нормально. Но повторяю - это половинчатое решение...

Автор: chekist 20.6.2007, 13:57
Круто!  А существует способ работы с Cookies без CookieManager ?
Как-нибудь их вручную вытаскивать из Responce и вставлять в Request через свойства IdHTTP.

Автор: aktuba 20.6.2007, 14:36
Цитата

Круто!  А существует способ работы с Cookies без CookieManager ?
Как-нибудь их вручную вытаскивать из Responce и вставлять в Request через свойства IdHTTP.


Ты не понял - они даже в Response не попадают... С куками можно работать через WinInet, но это уже не так просто, как с Indy.

Автор: chekist 20.6.2007, 18:19
В ообщем, спасибо aktuba за помощь и потраченное на нее время. 

Проект дальше будет писаться на Builder'e. Там есть один замечательный компонент - Fast Net  NMHTTP. В нем с куками тоже не все в порядке, но по крайней мере есть прямой доступ к Header и Cookie, и если что, нужные данные можно распарсить. 

Также благодарю Snowy за его маппер.

Удачи!

Автор: Snowy 20.6.2007, 20:17
chekist, в TIdHttp тоже можно к хедерам обращаться.
А FastNet уже устарел и больше не поддерживается.
В новых версиях билдера его уже нет.
Так что возникнут проблемы с переходом на новую версию билдера.
Видать старый билдер у тебя. 6-й небось. В 6-й дельфи эти компоненты тоже были...

Автор: aktuba 20.6.2007, 22:34
Цитата

Проект дальше будет писаться на Builder'e. Там есть один замечательный компонент - Fast Net  NMHTTP. В нем с куками тоже не все в порядке, но по крайней мере есть прямой доступ к Header и Cookie, и если что, нужные данные можно распарсить. 


=)))) А чем тебе уже готовое решение не угодило?

Автор: chekist 20.6.2007, 22:59
Всем угодило. Переход на Builder связан с тем, что те, кто будет со мной работать, не знают Delphi.  

Автор: chekist 6.10.2008, 10:09
Проект на C++ Builder

Автор: DDDsa 4.3.2009, 17:20
Цитата(aktuba @ 20.6.2007,  03:53)
chekist, за такую задачку я бы тебе поставил плюс, но думаю рановато для тебя =)

Итак. Задачка действительно оказалась интересной и, не скрою, я ее не до конца еще решил... Надо будет покопаться поглубже, для того чтобы найти красивое решение. Но если в кратце, то проблема в следующем. Вот так выглядит установка куков для этого сайта:
Код

Set-Cookie: remixchk=2; expires=Thu, 19-Jun-2008 00:55:33 GMT; path=/; domain=.vkontakte.ru
Set-Cookie: remixmid=23452; expires=Thu, 19-Jun-2008 00:55:33 GMT; path=/; domain=.vkontakte.ru
Set-Cookie: remixemail=aktuba%40yandex.ru; expires=Thu, 19-Jun-2008 00:55:33 GMT; path=/; domain=.vkontakte.ru
Set-Cookie: remixpass=52120febf525e8abeb9c95e9dce2c930; expires=Thu, 19-Jun-2008 00:55:33 GMT; path=/; domain=.vkontakte.ru


Вся проблема кроется в том, что в куках прописано на какой домен ставить эту куку: path=/; domain=.vkontakte.ru
Браузеры такое глотают легко, просто отбрасывая точку впереди, а вот Indy на этом валиться по следующей причине:

Код

  ACookie.CookieText := ACookieText;

  if Length(ACookie.Domain) = 0 then LDomain := AHost
  else LDomain := ACookie.Domain;

  ACookie.Domain := LDomain;

  if ACookie.IsValidCookie(AHost) then
  begin
    if DoOnNewCookie(ACookie) then
    begin
      FCookieCollection.AddCookie(ACookie);
    end
    else begin
      ACookie.Collection := nil;
      ACookie.Free;
    end;
  end
  else begin
    ACookie.Free;
  end;


Тут видно, что именно для .vkontakte.ru будут ставиться куки, а не для vkontakte.ru. Если покопаться дальше, то можно найти вот такие сравнения:
Код

Result := ((IndyPos('.', S) = 0) or (S[1] <> '.')) and NOT IsValidIP(S);


Как не трудно понять - эти сравнения всегда будут давать False, если домен, для которого устанавливается кука, впереди содержит точку. Вот и вся проблема =)))) Решение, на данный момент, простое. В модуль IdCookieManager, в процедуру DoAdd надо добавить одну строку:
Код

if LDomain[1] = '.' then LDomain := Copy(LDomain, 2, Length(LDomain) - 1);


Теперь эта процедура будет выглядеть так:
Код

procedure TIdCookieManager.DoAdd(ACookie: TIdCookieRFC2109; ACookieText, AHost: String);
Var
  LDomain: String;
begin
  ACookie.CookieText := ACookieText;

  if Length(ACookie.Domain) = 0 then LDomain := AHost
  else LDomain := ACookie.Domain;

  if LDomain[1] = '.' then LDomain := Copy(LDomain, 2, Length(LDomain) - 1);
  ACookie.Domain := LDomain;

  if ACookie.IsValidCookie(AHost) then
  begin
    if DoOnNewCookie(ACookie) then
    begin
      FCookieCollection.AddCookie(ACookie);
    end
    else begin
      ACookie.Collection := nil;
      ACookie.Free;
    end;
  end
  else begin
    ACookie.Free;
  end;
end;


После этого все работает нормально. Но повторяю - это половинчатое решение...

Странно, в D2009 модуль IdCookieManager переписан, а эта проблема не исправлена. Чинится этим же способом

Автор: Валерия 17.5.2009, 02:00
А как переписать процедуру  TIdCookieManager?
Где этот код?)

Автор: KaKTyCc 23.5.2009, 16:25
Тоже не понятно, как внести изменения в процедуру, чтобы куки сохранялись

Добавлено через 10 минут и 9 секунд
У меня сейчас так выглядит эта процедура

Код

procedure TIdCookieManager.DoAdd(ACookie: TIdCookieRFC2109; ACookieText, AHost: String);
begin
  ACookie.CookieText := ACookieText;

  if Length(ACookie.Domain) = 0 then begin
    ACookie.Domain := AHost;
  end;

  if not IsRejectedCookie(ACookie, AHost) then
  begin
    if DoOnNewCookie(ACookie) then
    begin
      FCookieCollection.AddCookie(ACookie);
      Exit;
    end;
    ACookie.Collection := nil;
  end;

  ACookie.Free;
end;

Автор: MetalFan 23.5.2009, 16:42
у меня (Indy 10.2.3) DoAdd выглядит так:
Код

procedure TIdCookieManager.DoAdd(ACookie: TIdCookieRFC2109; ACookieText, AHost: String);
Var
  LDomain: String;
begin
  ACookie.CookieText := ACookieText;

  if Length(ACookie.Domain) = 0 then LDomain := AHost
  else LDomain := ACookie.Domain;

  ACookie.Domain := LDomain;

  if ACookie.IsValidCookie(AHost) then
  begin
    if DoOnNewCookie(ACookie) then
    begin
      FCookieCollection.AddCookie(ACookie);
    end
    else begin
      ACookie.Collection := nil;
      ACookie.Free;
    end;
  end
  else begin
    ACookie.Free;
  end;
end;

Предлагаю в строке 7 сделать замену на сл.:
Код

  if Length(ACookie.Domain) = 0 then LDomain := DomainName(AHost)

по идее должно работать, но проверить не на чем)

Автор: KaKTyCc 23.5.2009, 17:27
Трассирую и обнаружил что в процедуре
Код


unit IdHTTP;

procedure TIdCustomHTTP.DoRequest(const AMethod: TIdHTTPMethod;
  AURL: string; ASource, AResponseContent: TStream;
  AIgnoreReplies: array of SmallInt);

...

    if not Response.KeepAlive then begin
      Disconnect;
    end;




Заходит в Disconnect

Добавлено через 11 минут и 37 секунд
Не помогает ничего

После такой штуки

Код

try
     IdHTTP1.Post('http://romzolik.ucoz.ru/index/sub/', params, response);
     Memo2.Lines.Add(idHttp1.ResponseText);
     Memo2.Lines.Add(IdHTTP1.Response.Location);
     Memo1.Clear;
     Memo1.Lines.Add(idhttp1.Get(IdHTTP1.Response.Location));
   finally
      params.Free;
      response.Free;
   end;


получаю 


Код

HTTP/1.1 403 Forbidden
Server: uServ/1.1.0
Date: Sat, 23 May 2009 12:56:40 GMT
Content-Type: application/octet-stream
Transfer-Encoding: chunked
Connection: keep-alive
Keep-Alive: timeout=15



Автор: MetalFan 23.5.2009, 17:39
KaKTyCc, и что из этого? может это нормальное поведение

Автор: KaKTyCc 23.5.2009, 17:45
Ок, может быть.
Тогда вопрос, если я авторизовался на сервере,
сделал POST и т.д. 
тогда GET должен вернуть страницу на которой я авторизован? и соответственно я могу там заполнить еще одну форму и отправить?

я правильно все понимаю?


Автор: MetalFan 23.5.2009, 19:05
все зависит от правильной обработки куков

Автор: Валерия 25.5.2009, 18:48
Я не совсем поняла как найти этот файл, который нужно править, что бы точка в начале домена кук не влияла

Автор: Демо 25.5.2009, 19:34
IdHTTP1.Post разве не возвращает результат?

Автор: Antimol 27.6.2009, 00:09
S:=IdHTTP1.Response.RawHeaders.CommaText - для получения всего ответа от сервера (вместе с кукисами)

Автор: creas0ft 28.5.2010, 00:46
Апну старый топик, как в нынешнем свежем кукименджере сменить чтобы точки понимал. ((

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)