LibCurl, Aktion nach Login

07/16/2015 00:49 Krabat2#1
Hallo :)

Ich hab mal wieder ne Frage bzw ein Problem.

Ich habe bisher nur ein Code um mich in ein Browsergame einzuloggen, jedoch weiß ich nicht wie ich danach eine bestimmte Aktion ausführen kann, z.B. ein Feld nach Links.

So sieht mein Code bisher aus:
PHP Code:
#include <stdio.h>
#include <curl/curl.h>
#include <iostream>
int main(void)
{
    
CURL *post;
    

    
    
curl_global_init(CURL_GLOBAL_ALL);

    
    
post curl_easy_init();
    if (
post) {
        
        
curl_easy_setopt(postCURLOPT_URL"http://XXX.XXX.de/XXX/XXX/index.php");
        
        
curl_easy_setopt(postCURLOPT_POSTFIELDS"name=XXX&password=XXX&submit=Einloggen");

        
        
curl_easy_perform(post)

        
        
curl_easy_reset(post);
        
curl_easy_setopt(postCURLOPT_URL"http://XXX.XXX.de/XXX/XXX/map.php?walk=left&intwalkid=546995750");
        
curl_easy_perform(post);
        
curl_easy_cleanup(post);
    }
    
curl_global_cleanup();
    
std::cin.get();
    return 
0;

Das Einloggen funktioniert auf alle Fälle.

Auf der Website steht, dass die "Easy" Methode nur für einen Post ist.

Weiß einer wie ich das Problem lösen kann?
07/16/2015 02:42 ichwillkeinevieren#2
[Only registered and activated users can see links. Click Here To Register...]
Wenn du was hilfreiches gefunden hast bitte posten, werde ich noch später gebrauchen xD
07/16/2015 07:34 Jeoni#3
Ich vermute nicht, dass es am falschen Request-Typ liegt. Ich denke, libcurl nimmt automatisch GET, wenn keine POST-Daten angegeben sind; sicher bin ich mir da aber auch nicht.
Aber bei der Response, die du vom Einloggen erhältst, werden in der Regel Cookies gesetzt. Diese dienen als Identifikation für die Session. Das heißt, dass du sie auch bei Folgeaktionen, für welche du eingeloggt sein musst, gesetzt haben musst. Ich nehme an, dass dem aktuell nicht so ist. Code kann ich dir dazu auch nicht geben, habe bisher nur wenig mit libcurl gearbeitet und das meiste schon wieder vergessen. Aber Cookies als Stichwort sollte dir schonmal weiterhelfen.
Mit freundlichen Grüßen
Jeoni
07/16/2015 08:35 ƬheGame#4
[Only registered and activated users can see links. Click Here To Register...]
07/16/2015 23:13 Krabat2#5
Danke schonmal für diese Hinweise :)

Also wenn ich es richtig verstanden habe:

1. Cookie beim Login speichern.
2. Cookie beim bewegen verwenden

um den Cookie zu speichern habe ich diese Option gefunden

Code:
CURLOPT_COOKIEJAR

Tell libcurl to activate the cookie engine, and when the easy handle is closed save all 
known cookies to the given cookiejar file. Write-only.

und um dieses wieder zu verwenden diese Option:
Code:
 CURLOPT_COOKIEFILE

Tell libcurl to activate the cookie engine, and to read the initial set of cookies from 
the given file. Read-only.
Wie schon erwähnt funktioniert der Login, jedoch escheint normalerweise im Chat dieser Text "XY loggt sich ein"

Doch dieser Text erscheint nicht obwohl ich keinen Error erhalte
07/17/2015 20:10 Delinquenz#6
Man kann Cookies auch aus den Response Headern auslesen, was ich auch eher empfehlen würde, weil man die Cookies dann auch bearbeiten und speichern kann.

Die folgende Funktion kannst du als CURLOPT_WRITEFUNCTION benutzen um den Response Body in eine std::string Variable zu speichern oder eben als CURLOPT_HEADERFUNCTION um den Response Header in eine std::string Variable zu speichern.

Code:
std::size_t writeToString(char* data, std::size_t size, std::size_t nmemb, std::string* string)
{
	if (!string)
	{
		return 0;
	}

	string->append(data, size * nmemb);

	return size * nmemb;
}
Wie macht man das?

Code:
CURL* handle = curl_easy_init();
std::string body;
std::string header;

// ...
// other settings like url
// ...

// save body
curl_easy_setopt(handle, CURLOPT_WRITEDATA, &body);
curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, writeToString);

// save header
curl_easy_setopt(handle, CURLOPT_HEADERDATA, &header);
curl_easy_setopt(handle, CURLOPT_HEADERFUNCTION, writeToString);

CURLcode result = curl_easy_perform(handle);

if (result != CURLE_OK)
{
  // do error handling
}
Nun hast du den Response Body in der Variable body und den Response Header in der Variable header gespeichert. Wie ist ein Header aufgebaut?

So könnte ein Header, den du als Antwort auf dein Post Request kriegst, aussehen.

Code:
HTTP/1.0 200 OK
Date: Fri, 31 Dec 1999 23:59:59 GMT
Set-Cookie: sessionToken=abc123; Expires=Wed, 09 Jun 2021 10:18:14 GMT
Content-Type: text/html
Content-Length: 1354
Was wäre für uns interessant? Die Set-Cookie Direktive natürlich. Wie filtern wir diese bloß? Dafür gibt es reguläre Ausdrücke, in C++ auch unter std::regex zu finden.

Code:
std::regex regex("Set-Cookie: ([^=]+?)=([^;]+?);");
std::string cookies;

// get cookies
for (std::sregex_iterator it(header.cbegin(), header.cend(), regex), end_it; it != end_it; ++it)
{
	cookies += it->str(1) + "=" + it->str(2) + ";";
}
W-was!?!? Es sieht komplizierter aus, als es tatsächlich ist.

In der ersten Zeile initialisieren wir einen regulären Ausdruck, der eben dazu da ist, um die Set-Cookie Direktiven herauszufiltern. Direktiven? Ja, es bleibt nämlich nur selten bei einem Cookie. Meistens findet man im Response Header mehr als nur eine Set-Cookie Direktive. Den regulären Ausdruck ansich werde ich nicht erklären, dafür gibt es Google.
In der darauffolgenden Zeile wird die Variable cookies definiert, in die wir die gefilterten Cookies speichern. Wir speichern sie auch direkt in einem Format, mit dem libcurl problemlos umgehen kann.
Für die for-Schleife sollten dir Iteratoren nicht ganz fremd sein: Hier wird durch den header String iteriert anhand des oben initialisierten regulären Ausdruckes, für jeden "Fund" wird der "Body" der for-Schleife ausgeführt. it->str(n) gibt immer die n-te "Capture Group" des regulären Ausdrückes zurück, in unserem Fall also it->str(1) für den Namen und it->str(2) für den Wert des Cookies.

Nun haben wir in unserem Fall einen String mit dem Inhalt sessionToken=abc123;. Wie benutzen wir ihn nun beim nächsten Request?

Code:
CURL* handle2 = curl_easy_init();

// ...
// other options like url
// ...

curl_easy_setopt(handle2, CURLOPT_COOKIE, cookies.c_str());
Wieso std::string::c_str()? Weil libcurl eine C Bibliothek ist und somit kein std::string erkennt. Sollte irgendwann mal deine Applikation abstürzen, kann es sehr gut daran liegen, dass du irgendwo einen Datentyp übergeben hast, mit dem libcurl nicht klarkommt. Pointer stellen da eine Ausnahme dar, weshalb das Beispiel von oben auch problemlos funktioniert.

Voila.