Reputation: 2893
I am having a little problem with something. I have the following code which uses cURL to log into a website, posting all the required data
<?php
$url = "https://someurl/login.aspx";
$ckfile = tempnam("/tmp", "CURLCOOKIE");
$useragent = $_SERVER['HTTP_USER_AGENT'];
$username = "[email protected]";
$password = "somepassword";
$f = fopen('log.txt', 'w');
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_COOKIEJAR, $ckfile);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_USERAGENT, $useragent);
$html = curl_exec($ch);
curl_close($ch);
preg_match('~<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="(.*?)" />~', $html, $viewstate);
preg_match('~<input type="hidden" name="__EVENTVALIDATION" id="__EVENTVALIDATION" value="(.*?)" />~', $html, $eventValidation);
$viewstate = $viewstate[1];
$eventValidation = $eventValidation[1];
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, false);
curl_setopt($ch, CURLOPT_COOKIEJAR, $ckfile);
curl_setopt($ch, CURLOPT_COOKIEFILE, $ckfile);
curl_setopt($ch, CURLOPT_HEADER, FALSE);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_REFERER, $url);
curl_setopt($ch, CURLOPT_VERBOSE, 1);
curl_setopt($ch, CURLOPT_STDERR, $f);
curl_setopt($ch, CURLOPT_USERAGENT, $useragent);
$postfields = array();
$postfields['__EVENTTARGET'] = "";
$postfields['__EVENTARGUMENT'] = "";
$postfields['__VIEWSTATE'] = $viewstate;
$postfields['__EVENTVALIDATION'] = $eventValidation;
$postfields['btnLogin'] = "Login";
$postfields['txtPassword'] = $password;
$postfields['txtUserName'] = $username;
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $postfields);
$ret = curl_exec($ch);
So the above code works fine. I do not close curl yet because I need to keep the cookie active. Anyways, once I have logged in using the above, I do
if($ret) {
curl_setopt($ch, CURLOPT_URL, 'https://someurl.com/financial/quote.aspx?id=12345');
curl_setopt($ch, CURLOPT_POST, 0);
$data = curl_exec($ch);
var_dump($data);
}
I can see from the output that I am now on the correct page. However, in the example above, I do not post anything. The page which I go too has a button on it. When looking at what is posted by this button within Firebug I see this
__EVENTARGUMENT
__EVENTTARGET
__EVENTVALIDATION fsudifhsiudgfiusgdf
__VIEWSTATE
__VIEWSTATE_GUID 0f26cc24-ef59-4bc7-87c0-141833df148b
ctl00$PageContent$btn2 Accepted
As such, I have tried to replicate the pushing of this button by doing the following
if($ret) {
curl_setopt($ch, CURLOPT_URL, 'https://someurl.com/financial/quote.aspx?id=12345');
$postfieldsInner = array();
$postfieldsInner['__EVENTTARGET'] = "";
$postfieldsInner['__EVENTARGUMENT'] = "";
$postfieldsInner['__VIEWSTATE'] = "";
$postfieldsInner['__VIEWSTATE_GUID'] = $viewstate;
$postfieldsInner['__EVENTVALIDATION'] = $eventValidation;
$postfieldsInner['ctl00$PageContent$btn2'] = "Accepted";
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $postfieldsInner);
$content = curl_exec($ch);
if (!$content) {
echo 'An error has occurred: ' . curl_error($ch);
} else {
var_dump($content);
}
}
This time however, the button action does not seem to occur. Am I missing something when making the second request?
Thanks
Upvotes: 0
Views: 1215
Reputation: 42685
So, a couple of things jump out at me:
You're assuming that the magic values for __VIEWSTATE
and __EVENTVALIDATION
won't change. This is unlikely to be the case. You should pull those values again after fetching the data page.
You're passing the $viewstate
variable as the value for __VIEWSTATE
on the initial login, but you leave that blank on the subsequent post and instead pass $viewstate
as __VIEWSTATE_GUID
. Not sure if this is intentional or not.
You're using an array for CURL_POSTFIELDS
which may cause problems. The documentation says:
Passing an array to
CURLOPT_POSTFIELDS
will encode the data as multipart/form-data, while passing a URL-encoded string will encode the data as application/x-www-form-urlencoded.
And, very important, do NOT disable certificate validation, fix your server setup instead.
A few other suggestions, perhaps more a matter of style than substance though.
Passing an empty string as CURLOPT_COOKIEFILE
will enable session handling without the need to save to a file.
You don't need to do curl_close()
and curl_init()
multiple times in a script; just reuse the existing handle. This saves having to redefine the options and reuse the session cookies.
Use curl_setopt_array()
for cleaner code.
curl_exec()
returns false
on error, you should check for it explicitly.
Here's how I'd clean up the code:
<?php
$url = "https://someurl/login.aspx";
$ckfile = tempnam("/tmp", "CURLCOOKIE");
$useragent = $_SERVER['HTTP_USER_AGENT'];
$username = "[email protected]";
$password = "somepassword";
$viewstate_pattern = '~<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="(.*?)" />~';
$eventval_pattern = '~<input type="hidden" name="__EVENTVALIDATION" id="__EVENTVALIDATION" value="(.*?)" />~';
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => $url,
CURLOPT_COOKIEFILE => "",
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_USERAGENT => $useragent,
]);
// Getting the login form
$html = curl_exec($ch);
if ($html !== false) {
preg_match($viewstate_pattern, $html, $viewstate);
preg_match($evenval_pattern, $html, $eventValidation);
$viewstate = $viewstate[1];
$eventValidation = $eventValidation[1];
$postfields = http_build_query([
"__EVENTTARGET"=>"",
"__EVENTARGUMENT"=>"",
"__VIEWSTATE"=>$viewstate,
"__EVENTVALIDATION"=>$eventValidation,
"btnLogin"=>"Login",
"txtPassword"=>$password,
"txtUserName"=>$username,
]);
curl_setopt_array($ch, [
CURLOPT_REFERER=>$url,
CURLOPT_POST=>true,
CURLOPT_POSTFIELDS=>$postfields,
]);
// Submitting the login form
$html = curl_exec($ch);
if ($html !== false) {
curl_setopt_array($ch, [
CURLOPT_URL=>'https://someurl.com/financial/quote.aspx?id=12345',
CURLOPT_POST=>false,
]);
// Getting the data page
$html = curl_exec($ch);
if ($html !== false) {
preg_match($viewstate_pattern, $html, $viewstate);
preg_match($evenval_pattern, $html, $eventValidation);
$viewstate = $viewstate[1];
$eventValidation = $eventValidation[1];
$postfieldsInner = http_build_query([
"__EVENTTARGET"=>"",
"__EVENTARGUMENT"=>"",
// Should this be empty?
"__VIEWSTATE"=>"",
"__VIEWSTATE_GUID"=>$viewstate,
"__EVENTVALIDATION"=>$eventValidation,
'ctl00$PageContent$btn2'=>"Accepted",
]);
curl_setopt_array($ch, [
CURLOPT_POST=>true,
CURLOPT_POSTFIELDS=>$postfieldsInner,
]);
// Posting the data page
$html = curl_exec($ch);
if ($html === false) {
echo 'An error has occurred: ' . curl_error($ch);
} else {
var_dump($html);
}
} else {
// Error getting the data page
}
} else {
// Error submitting the login page
}
} else {
// Error getting the login page
}
curl_close();
Upvotes: 1