I'm trying to write some PHPUnit tests for ajax endpoints. I can do this no sweat when the user doesn't have to be logged in. But to test the endpoint in question, the user does have to be logged in and I want to get the cookie programmatically as part of the test. Basically the test I want to run looks like:
$url = "https://example.com/ajax/endpoint";
$fields = array(
'name'=>'test '.rand(),
'host'=>rand(0,255).'.'.rand(0,255).'.'.rand(0,255).'.'.rand(0,255),
'port'=>rand(1,1000)
);
$fields_string = "";
foreach ($fields as $key=>$value) {
$fields_string .= $key.'='.$value.'&';
}
$fields_string = rtrim($fields_string, '&');
ob_start();
$ch = curl_init();
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $fields_string);
curl_setopt($ch, CURLOPT_COOKIE, $userCookie);
curl_setopt($ch, CURLOPT_URL, $url);
$response = curl_exec($ch);
$this->assertEquals(true, $response);
$json = ob_get_contents();
$return = json_decode($json);
$this->assertEquals('false', $return->success);
$this->assertEquals('', $return->data);
ob_end_clean();
But I don't know a good way to get $userCookie other than opening a browser, logging in, and then reading PHPSESSID from the cookies in the browser. How can I get the cookie for this without grabbing it manually? I'd like to be able to get it from a curl request to the login endpoint:
$url = "https://example.com/ajax/login";
$fields = array(
'username'=>$username,
'password'=>$password
);
$fields_string = "";
foreach ($fields as $key=>$value) {
$fields_string .= $key.'='.$value.'&';
}
$fields_string = rtrim($fields_string, '&');
$ch = curl_init();
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $fields_string);
curl_setopt($ch, CURLOPT_URL, $url);
$response = curl_exec($ch);
Does anything stop you to grab it programmatically?
$ch = curl_init('https://example.com/login');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, "login=root&password=toor");
curl_setopt($ch, CURLOPT_HEADER, 1);
$result = curl_exec($ch);
preg_match_all('/^Set-Cookie: PHPSESSID=(.*?);/mi', $result, $matches);
$userCookie = $matches[1];
You're halfway there with your login cURL request. What you need to do is retrieve the cookie from the response headers to get the PHPSESSID.
How to get response headers with cURL has been asked in another question you can find here.
Once you've got the response headers, you'll have to parse it to get the Set-Cookie header. Using the content of that header for your subsequent tests should work from there.
Related
Context: I have a WordPress plugin that allows users to authenticate with Bitly so that they can use link shortening features if they desire to do so.
Bitly requires one callback URL to be stored in the app settings, so I created a standalone script on my server that processes the authentication process. The overall handshake actually looks something like this:
The user clicks a link taking them to the Bitly authorization page for my app.
If they agree, they are forwarded to my script with a code.
My script exchanges that code to Bitly for another code.
Once the codes are all acquired, it reaches out to the user's domain to store the codes and to retreive the URL of the options page on that user's URL so that we can redirect the user back home.
We then redirect the user back to the options page that they had just clicked away from.
Problem: However, a very small handful of users are getting the following error just prior to the authentication process being complete:
Warning: Header may not contain more than a single header, new line
detected in /home/warfarep/public_html/bitly_oauth.php on line 72.
Sample Code:
function sw_file_get_contents_curl($url){
$ch=curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']);
curl_setopt($ch, CURLOPT_FAILONERROR, 0);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_TIMEOUT, 5);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
curl_setopt($ch, CURLOPT_NOSIGNAL, 1);
curl_setopt($ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
$cont = #curl_exec($ch);
$curl_errno = curl_errno($ch);
curl_close($ch);
if ($curl_errno > 0) {
return 0;
}
return $cont;
}
// Check if this is the first pass and we have the generic code
if(isset($_GET['code'])):
// Retreive the information
$code = $_GET['code'];
$client_ID = 'blahblahblah';
$client_secret = 'blahblahblah';
$redirect_url = 'blahblahblah';
$state = $_GET['state'];
$url = 'https://api-ssl.bitly.com/oauth/access_token';
$fields = array(
'code' => urlencode($code),
'client_id' => urlencode($client_ID),
'client_secret' => urlencode($client_secret),
'redirect_uri' => urlencode($redirect_url),
'state' => urlencode($state)
);
//url-ify the data for the POST
foreach($fields as $key=>$value) { $fields_string .= $key.'='.$value.'&'; }
rtrim($fields_string, '&');
//open connection
$ch = curl_init();
//set the url, number of POST vars, POST data
curl_setopt($ch,CURLOPT_URL, $url);
curl_setopt($ch,CURLOPT_POST, count($fields));
curl_setopt($ch,CURLOPT_POSTFIELDS, $fields_string);
curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
curl_setopt($ch,CURLOPT_HTTPHEADER, array('Accept: application/json'));
//execute post
$response = curl_exec($ch);
//close connection
curl_close($ch);
$response = json_decode($response , true);
$ajax_url = $state .= '?action=sw_bitly_oauth&access_token='.$response['access_token'].'&login='.$response['login'];
$wp_response = sw_file_get_contents_curl($ajax_url);
$wp_response = rtrim($wp_response , '0');
header('Location: '.$wp_response);
^^^^^^ This is line 72 from the error message
endif;
Question: Is there anything that you can see that would prevent headers from already being sent prior to the redirect on line 72? How do I fix this Bitly oauth "single header" error? Thanks!
I'm not able to post values to field and process further steps to download a file. Could anyone suggest where I'm going wrong?
extract($_POST);
$url=header("Location: http://gis.lntecc.com/bwssblnt/Scada.aspx? field1=Kathriguppe%2cSW2DM0402%2c235505H073%2c450");
$fields =array(
"TextBoxFromDate" => urlencode("2014-10-01"),
"TextBoxToDate" => urlencode("2014-10-09")
);
foreach($fields as $key => $value)
$fields_string .= $key.'='.$value.'&';
rtrim($fields, '&');
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, count($fields));
curl_setopt($ch, CURLOPT_POSTFIELDS, $fields_string);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$result = curl_exec($ch);
echo $result;
curl_close($ch);
Where did I make a mistake since I'm not able to post values to the field?
Simply remove that huge space in your URL:
$url=header("Location: http://gis.lntecc.com/bwssblnt/Scada.aspx? field1=Kathriguppe%2cSW2DM0402%2c235505H073%2c450");
Becomes:
$url=header("Location: http://gis.lntecc.com/bwssblnt/Scada.aspx?field1=Kathriguppe%2cSW2DM0402%2c235505H073%2c450");
My code is:
<?php
extract($_POST);
$url = "http://www.domain.com/";
$fields = array(
'myparam1' => 'something',
);
foreach($fields as $key=>$value) { $fields_string .= $key.'='.$value.'&'; }
rtrim($fields_string, '&');
//open connection
$ch = curl_init();
curl_setopt($ch,CURLOPT_URL, $url);
curl_setopt($ch,CURLOPT_POST, count($fields));
curl_setopt($ch,CURLOPT_POSTFIELDS, $fields_string);
//curl_setopt($ch,CURLOPT_RETURNTRANSFER, false);
$result = curl_exec($ch);
print_r("+");
curl_close($ch);
?>
The problem is it show the response in the web browse , but i dont want to. any help would be appreciated.
You have a comment on this line:
//curl_setopt($ch,CURLOPT_RETURNTRANSFER, false);
You should enable this line and set the value to true
curl_setopt($ch,CURLOPT_RETURNTRANSFER, true);
As you can see on the man page here that option is used this way:
TRUE to return the transfer as a string of the return value of
curl_exec() instead of outputting it out directly.
The option CURLOPT_RETURNTRANSFER will return the output rather than printing it.
curl_setopt($ch,CURLOPT_RETURNTRANSFER, true);
CURLOPT_POSTFIELDS can take array directly and CURLOPT_RETURNTRANSFER should be true
$url = "http://www.php.net";
$fields = array(
'myparam1' => 'something'
);
// open connection
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, count($fields));
curl_setopt($ch, CURLOPT_POSTFIELDS, $fields);
curl_setopt($ch,CURLOPT_RETURNTRANSFER, true);
$result = curl_exec($ch);
curl_close($ch);
I think this url will help you.
Get data or Content from a URL using cURL PHP
This is my cURL POST function:
public function curlPost($url, $data)
{
$fields = '';
foreach($data as $key => $value) {
$fields .= $key . '=' . $value . '&';
}
rtrim($fields, '&');
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, count($data));
curl_setopt($ch, CURLOPT_POSTFIELDS, $fields);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
$result = curl_exec($ch);
$info = curl_getinfo($ch);
curl_close($ch);
}
$this->curlPost('remoteServer', array(data));
How do I read the POST on the remote server?
The remote server is using PHP... but what var in $_POST[] should I read
for e.g:- $_POST['fields'] or $_POST['result']
You code works but i'll advice you to add 2 other things
A. CURLOPT_FOLLOWLOCATION because of HTTP 302
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, TRUE);
B. return in case you need to output the result
return $result ;
Example
function curlPost($url, $data) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, TRUE);
$result = curl_exec($ch);
$info = curl_getinfo($ch);
curl_close($ch);
return $result;
}
print(curlPost("http://yahoo.com", array()));
Another Example
print(curlPost("http://your_SITE", array("greeting"=>"Hello World")));
To read your post you can use
print($_REQUEST['greeting']);
or
print($_POST['greeting']);
as a normal POST request ... all data posted can be found in $_POST ... except files of course :) add an &action=request1 for example to URL
if ($_GET['action'] == 'request1') {
print_r ($_POST);
}
EDIT: To see the POST vars use the folowing in your POST handler file
if ($_GET['action'] == 'request1') {
ob_start();
print_r($_POST);
$contents = ob_get_contents();
ob_end_clean();
error_log($contents, 3, 'log.txt' );
}
here's my code:
<?php
$url = 'http://localhost:2304/index.php/testproj/files/add/';
$name = "test";
$fields = array(
'name'=>urlencode($name)
);
$fields_string = "";
foreach($fields as $key=>$value) {
$fields_string .= $key.'='.$value.'&';
}
rtrim($fields_string,'&');
//open connection
$ch = curl_init();
//set the url, number of POST vars, POST data
curl_setopt($ch,CURLOPT_URL,$url);
curl_setopt($ch,CURLOPT_POST,count($fields));
curl_setopt($ch,CURLOPT_POSTFIELDS,$fields_string);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
//execute post
$result = curl_exec($ch);
var_dump($result);
//close connection
curl_close($ch);
?>
I am trying to send post data to a CodeIgniter controller. I decided to use CURL to do the job. however, it doesn't work, when I put "blah" in my controller, it doesn't return anything. When I access the URL directly, it shows "blah".
You could use my Curl library:
$this->load->library('curl');
$result = $this->curl->simple_get('http://example.com/');
var_dump($result);
Try adding this into options
$ch = curl_init();
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
Edit 1
add this
curl_setopt($ch, CURLOPT_HEADER, 1);
// and post the result of $result