CURL call works in terminal, but it won't in PHP - php

I've been searching through extensively, but couldn't find any topics which are really related to my problem, so I decided to ask a new question...
I'm trying to issue a batch request to the Facebook Graph API using CURL, which works fine in Terminal, but it simply won't in PHP...
Steps to reproduce:
1.) Obtain an access token for yourself from the Graph API Explorer (no permissions needed, just a valid token) Link: http://developers.facebook.com/tools/explorer
2.) Paste it in the following terminal command: (PLEASE be careful, you need to paste it in 4 placeholders in total to work correctly!)
curl \
-F 'access_token=PASTE_ACCESS_TOKEN_HERE' \
-F 'batch=[{"method":"GET","relative_url":"fql?q=SELECT+name+FROM+user+WHERE+uid%3Dme%28%29&access_token=PASTE_ACCESS_TOKEN_HERE"},{"method":"GET","relative_url":"fql?q=SELECT+name+FROM+user+WHERE+uid%3Dme%28%29&access_token=PASTE_ACCESS_TOKEN_HERE"},{"method":"GET","relative_url":"fql?q=SELECT+name+FROM+user+WHERE+uid%3Dme%28%29&access_token=PASTE_ACCESS_TOKEN_HERE"}]' \
https://graph.facebook.com
3.) Execute it in terminal, it should return lots of headers, and your name 4 times in the body section (JSON encoded).
4.) Until now, everything should be working. Here comes the bad part, paste your token again in the 4 placeholders in the following PHP script:
<?php
$url = 'https://graph.facebook.com';
$fields = array(
'access_token' => 'PASTE_ACCESS_TOKEN_HERE',
'batch' =>
'[{"method":"GET","relative_url":"fql?q=SELECT+name+FROM+user+WHERE+uid%3Dme%28%29&access_token=PASTE_ACCESS_TOKEN_HERE"},{"method":"GET","relative_url":"fql?q=SELECT+name+FROM+user+WHERE+uid%3Dme%28%29&access_token=PASTE_ACCESS_TOKEN_HERE"},{"method":"GET","relative_url":"fql?q=SELECT+name+FROM+user+WHERE+uid%3Dme%28%29&access_token=PASTE_ACCESS_TOKEN_HERE"}]'
);
//url-ify the data for the POST
foreach($fields as $key=>$value) { $fields_string .= $key.'='.$value.'&'; }
$fields_string = 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);
//execute post
$result = curl_exec($ch);
//close connection
curl_close($ch);
print_r($result);
?>
6.) Run the code, and you should (at least I do...) get the following error message from Facebook: '{"error":{"message":"Malformed access token ACCESS_TOKEN_HERE....\"}]","type":"OAuthException","code":190}}1'
I guess that Facebook thinks that the JSON closing braces are part of the access token, and because of that it will return this error. I tried removing the escaped double quote and braces from the end of $fields['batch'] , but then it throws another error stating that the batch parameter must be a JSON string (obviously...)
Am I missing something or is this Facebook's fault (if so, I don't understand why the Terminal solution works...)?
Here are the official Facebook Docs BTW:
http://developers.facebook.com/docs/reference/api/batch
Thanks in advance!
EDIT:
I found a (temporary) workaround, this will work (of course, since it uses a shell script):
<?php
$result = shell_exec('curl \
-F \'access_token=PASTE_ACCESS_TOKEN_HERE\' \
-F \'batch=[{"method":"GET","relative_url":"fql?q=SELECT+name+FROM+user+WHERE+uid%3Dme%28%29&access_token=PASTE_ACCESS_TOKEN_HERE"},{"method":"GET","relative_url":"fql?q=SELECT+name+FROM+user+WHERE+uid%3Dme%28%29&access_token=PASTE_ACCESS_TOKEN_HERE"},{"method":"GET","relative_url":"fql?q=SELECT+name+FROM+user+WHERE+uid%3Dme%28%29&access_token=PASTE_ACCESS_TOKEN_HERE"}]\' \
https://graph.facebook.com');
print_r(json_decode($result),true);
?>
Does somebody know why this is a worse solution (I suppose it is) than using PHP-cURL?
I read somewhere that you shouldn't use shell scripts in PHP, I don't know why though...
Thanks!

I ran the first half of your code just to see what the contents of $fields_string would be before starting any of the curl commands. For some reason rtrim is not removing the last ampersand in the string for me. Perhaps use this instead to remove the last character:
$fields_string = substr($fields_string, 0, -1);

Related

Replit Database. How would I embed the curl commands of the Replit Database into my php web server code?

I am creating a sign up page on my PHP web server on replit that involves the replit default database. I know that there are language clients for python, node, and go. How do I embed the curl commands into the PHP code. Currently, I am using the shell exec command to execute curls on the online shell. The curl commands I am using from repl.it are
curl $REPLIT_DB_URL -d 'key=value'
curl $REPLIT_DB_URL/key
curl -XDELETE $REPLIT_DB_URL/key
curl "$REPLIT_DB_URL?prefix=key"
They are used for setting keys to values, getting a key's value, deleting a key, and listing all keys respectively.
When I copy these commands and paste them into a PHP file like this,
<?php
$email = $_POST["email"];
$password = $_POST["password"];
curl $REPLIT_DB_URL -d '$email=$password';
curl $REPLIT_DB_URL/$email;
?>
I get this error:
syntax error, unexpected '$REPLIT_DB_URL' (T_VARIABLE)
Thank you in advance.
You can't just paste console commands into PHP code and expect them to work. The error you are getting is that it doesn't understand what $REPLIT_DB_URL is.
You are going to have to convert your console commands into PHP code.
$ch = curl_init('http://url-to-your-database-server');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
curl_setopt($ch, CURLOPT_POSTFIELDS, "{$email}={$password}");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$result = curl_exec($ch);
if ($result === false) {
// handle the error here
}
curl_close($ch);
Whether you need to json_encode the body (email and password pair) or not is up to how your database accepts the body. Your raw curl lines suggest maybe not. You may also need to json_decode the $result, maybe not.
Note that I have kept the $ch handler open for the error handling, you can get the code and response for an error with
curl_error($ch)
curl_errno($ch)
I have faced the same problem and I finally solved it. Here is the steps:
open Replit's terminal (shell) and execute this command: echo $REPLIT_DB_URL to get the database URL.
copy ReplitDB.php from Replit Database for PHP.
include or require it to your code, here is the code:
require __DIR__ .'/ReplitDB.php';
use \Dannsbass\ReplitDB;
$db = new ReplitDB(REPLIT_DB_URL); // get from terminal: echo $REPLIT_DB_URL
// set your data
$db->set_data('email', $your_email);
$db->set_data('password', $your_password);
// get all data keys
echo $db->get_keys();
// retrieve a specified data by its key
echo $db->get_data('email');
Please check Replit Database for PHP for documentation.

Curl via Wordpress

Hi I am having major problems and its driving me mad - 3 x php developers all say the code is right, but it still doesnt 'post' the data from the form into the seperate crm website. - which is clearly the whole point ! when someone submits a form i want their record to be created in my crm system
I have a wordpress site using formidable Pro form, that i want to send data to my crm system.
I think there is a problem with how wordpress sends or tells curl to work, - bit i'm not a tech person so my knowledge and understanding is a bit thin. Right now - i believe the code gets a 200 code which means its all ok - trouble is there is no data at the other end in my crm system - could anyone point out whats wrong ?
( ps posting url changed just so i dont break privacy rules on here , pps i have echoed out // a lot of the items just to see if i can get it to even just send the surname through )
The numbers in boxes are how formidable pro sees the data its collected ie surname is [861] is it the brackets that are causing an issue or is it the way the curl is dending the data - or is it wordpress !?
pps using 'code snippets' a php plugin for wordpress to enable the php code
code.........
add_action('frm_after_create_entry', 'after_entry_created', 30, 2);
function after_entry_created($entry_id, $form_id){
if($form_id == 21){
$url = 'https://secure4.mline.co.uk/DavidFarrell/php/NewMortgage.php';
$fields = array(
//Mandatory fields go here:
'MortgageMode' => urlencode(1), // OR 'CommercialMode => urlendcode(1), for CommercialKeeper
'StagePK' => urlencode(25),
'AdvisorPK' => urlencode(1),
'Surname1'=>urlencode($_POST['[861]']),
//Other fields to post into go here:
//Mortgage Details
//'LenderPK'=>urlencode(1),
//'InterestRateTypePK'=>urlencode(2),
//'Rate'=>urlencode(3.45),
//'DealTerm'=>urlencode(5),
//'Term'=>urlencode(25),
//'ActionPK'=>urlencode(11),
//'ActionText'=>urlencode($_POST['Notes']),
//Applicant Details
//'Forename1'=>urlencode($_POST['859']),
//'Email1'=>urlencode($_POST['Emailaddress'][864]),
//'DayPhone'=>urlencode($_POST['[867]']),
//'MobilePhone'=>urlencode($_POST['MobilePhone1'][866]),
//'Forename2'=>urlencode($_POST['[880]']),
//'Surname2'=>urlencode($_POST['[882]']),
//'MidNameApp1'=>urlencode($_POST['[860]']),
//'MidNameApp2'=>urlencode($_POST['[881]']),
//Submit is also mandatory and typically is placed at the end of your array
'submit'=>true
);
// Loops through the $fields array and results in a string variable called $fields_string which is a URL friendly string
foreach($fields as $key => $value)
{
//adds the key which is the eKeeper field followed by an '=', followed by and ampersand (&)
$fields_string.=$key.'='.$value.'&';
}
//trims any whitespace and cleans up the $fields_string variable
rtrim($fields_string,'&');
// Initialises a cURL connection
$ch = curl_init();
//Sets the URL to post into using the $url variable that was initialised earlier
curl_setopt($curl_connection, CURLOPT_POST, 1);
curl_setopt($ch,CURLOPT_URL,$url);
// Sets the number of fields to be passed, this is achieved by using the count() function to count the elements in the $fields array.
//curl_setopt($ch,CURLOPT_POST,count($fields));
// Sets the string that contains the eKeeper fields and their values ($fields_string)
curl_setopt($curl_connection, CURLOPT_POSTFIELDS, $post_string);
//curl_setopt($ch,CURLOPT_POSTFIELDS,$fields_string);
// Sets the return transfer option to true so that the return value after execution
// curl_setopt($ch,CURLOPT_RETURNTRANSFER,true);
curl_setopt($curl_connection, CURLOPT_RETURNTRANSFER, false);
// Executes the curl session. must not be done until after the session has been initilised and the relevant curl options have been set.
$result = curl_exec($ch);
// Closes the connection/curl session
curl_close($ch);
}
}
well, this part is definitely wrong
foreach($fields as $key => $value)
{
//adds the key which is the eKeeper field followed by an '=', followed by and ampersand (&)
$fields_string.=$key.'='.$value.'&';
}
//trims any whitespace and cleans up the $fields_string variable
rtrim($fields_string,'&');
neither the key nor the value is url encoded, so if the key or value contains ÆØÅ or spaces or & or a bunch of other characters, they will be encoded wrong. also that rtrim is NOT how you trim an urlencoded string at all, no idea how that got past 3 devs.
correcting that would be
foreach($fields as $key => $value)
{
$fields_string.=urlencode($key).'='.urlencode($value).'&';
}
if(!empty($fields)){
//remove the last &
$fields_string=substr($fields_string,0,-1);
}
but luckily, PHP has a built-in function for making x-www-form-urlencoded-formatted strings called http_build_query, so the entire code could be replaced with:
$fields_string.=http_build_query($fields);
which would basically do that entire encoding loop for you. other than that, you have a bunch of undefined variables, but i guess those are mostly just removed code (you state that you removed a bunch before posting it here), but if not, setting error_reporting=E_ALL in php.ini would notice you of of most of them (but not arrays, because php is stupid, arrays are implicitly created without warning when pushed to)
but, as i have said so many times before, when debugging curl requests, always enable CURLOPT_VERBOSE - do that, and post the CURLOPT_VERBOSE stderr log in your main post, with that log, we may be of more assistance

PHP cURL PUT request where data is array

I've got a cURL request that works from the command line, but I can't figure out how to translate it into the PHP implementation of cURL. I believe that my issue is with the formatting of the data that's being sent, but I'm not 100% sure that is the case. This is the curl command I want to send:
# curl -X PUT -d '{"shared_link": {"access":"open"}}' \
-H "Authorization: Bearer ACCESSCODE" https://api.example.com/files/12345
I know that command works! So here's how I'm trying to reproduce it in PHP (where I have a variety of other curl commands working, but none quite like this).
$url = 'https://api.example.com/files/1234';
$header = array('Authorization: Bearer ACCESSCODE');
$data = array('shared_link'=>array('access'=>'open'));
$ch = curl_init();
curl_setopt($ch,CURLOPT_URL,$url);
curl_setopt($ch,CURLOPT_CUSTOMREQUEST,'PUT');
curl_setopt($ch,CURLOPT_RETURNTRANSFER,true);
curl_setopt($ch,CURLOPT_POSTFIELDS,$data);
curl_setopt($ch,CURLOPT_HTTPHEADER,$header);
$output = curl_exec($ch);
curl_close($ch);
return $output;
What I expect to get (and what I do get, when running the command from the command line) is a JSON response from the API server containing all the info about the file, including a change to the 'shared_link' value. What I get instead is a JSON response containing all the info about the file, with the 'shared_link' value unchanged. This is identical to if I were sending a GET request, or a PUT request where the format of the data was valid, but which didn't match any of the file's fields that were possible to update.
So I don't know if the problem with my request is the format of the data (this is what I think is the most likely) or whether I'm correctly configuring curl to do a PUT. I believe I'm doing that the way I've seen it described in a number of other examples, but it still seems a bit strange to me, so I can't be totally sure I'm doing it correctly. In addition, there could be some other area where I'm making a mistake that I don't recognize!
I've tried a number of different ways of formatting the data, none of which worked for me, including:
// This fails with 400 bad request
$data = http_build_query(array('shared_link'=>array('access'=>'open')));
// So does this
$data = urlencode("shared_link[access]=open");
// This fails because the JSON gets converted into objects,
// which POSTFIELDS won't accept
$data = json_decode('{"shared_link": {"access":"open"}}');
I'm running out of things to try. Can someone help me figure out what I'm doing wrong? And if there's any relevant information that I've left out, just let me know and I'll be happy to provide it.
Thanks in advance.
EDIT:
So the answer, it turns out, was so obvious that I overlooked it!
All I had to do was:
$data = '{"shared_link": {"access": "open"}}'
So yeah, question answered. Thanks CBroe!
In my (sort of) defense, the documentation for CURLOPT_POSTFIELDS (http://php.net/manual/en/function.curl-setopt.php) says that the value for that option has to be either an array or a urlencoded string, which is what I was going on. So I was working under that assumption, which was clearly mistaken, since what worked is definitely neither an array nor a urlencoded string.
You can try this
$post_body = http_build_query(
array(
'shared_link[access]' => 'open'
)
);
After that, pass curl opt as curl_setopt($curl, CURLOPT_POSTFIELDS, urldecode($post_body));

Laravel 4 make post request from controller to external url with data

I am looking for a way to make a post request from a controller to an external url. The data being posted is a php array. The url to recieve is an ecommerce API in an external url. The post has to be done from the controller method. The url should reply with 'success', 'error', 'failure' or 'trylater' string. I have tried the following with no success:
return Redirect::to("https://backoffice.host.iveri.com/Lite/Transactions/New/Authorise.aspx", compact($array));
I have tried curl too:
$url = 'https://backoffice.host.iveri.com/Lite/Transactions/New/Authorise.aspx';
//url-ify the data for the POST
$fields_string ='';
foreach($array 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($array));
curl_setopt($ch,CURLOPT_POSTFIELDS, $fields_string);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
//execute post
$result = curl_exec($ch);
//close connection
curl_close($ch);
Part of the array being sent is the callbacks that the API uses to responds:
'Lite_Website_Successful_url' => 'https://mydomain.com/order/'.$order_id,
'Lite_Website_Fail_url' => 'https://mydomain.com/checkout/fail',
'Lite_Website_TryLater_url' => 'https://mydomain.com/checkout/trylater',
'Lite_Website_Error_url' => 'https://mydomain.com/checkout/error'
Please let me know how to do a POST request properly with data carried with it to an external url. An ajax post from the controller too would help but I have tried with no success. But I would prefer a laravel php answer more. Thank you.
We can use package Guzzle in Laravel, it is a PHP HTTP client to send HTTP requests.
You can install Guzzle through composer
composer require guzzlehttp/guzzle:~6.0
Or you can specify Guzzle as a dependency in your project's existing composer.json
{
"require": {
"guzzlehttp/guzzle": "~6.0"
}
}
Example code of POST Request in laravel, using Guzzle is as shown below,
use GuzzleHttp\Client;
class yourController extends Controller {
public function saveApiData()
{
$client = new Client();
$res = $client->request('POST', 'https://url_to_the_api', [
'form_params' => [
'client_id' => 'test_id',
'secret' => 'test_secret',
]
]);
$result= $res->getBody();
dd($result);
}
Let me clarify some stuff and try to point you in the right direction.
First, what you're attempting to do sounds like "making an API request from your web app". The difference in that wording in how I stated it vs yours is that it's more general.
You can make an API request anywhere in your application, not necessarily in your controller (Don't be afraid to make extra classes/models for things like API calls!)
I'm curious about why it "has to be" done in your controller? What's your use case?
AJAX doesn't exist on the server-side (in PHP). That's purely a javascript-specific "technology" that describes javascript making a request to a URL on the client-side.
Lastly, what are you trying to do? Do you need a user to be redirected? Or do you need to make an API call and parse the result within your application?
The cURL request you've attempted should work for making an API request. That's one of the main ways of making an API request within PHP code. It won't, however, allow a user on the front-end to see that request being made and processed. With cURL (and any API request), the processing is all happening behind the scenes in your PHP (which your users can't see).
Either use CURL the way you've been trying, or check this thread for a brief answer on doing it with the Guzzle http client. Guzzle seems to be the preferred client for use with Laravel...
Call external API function from controller, LARAVEL 4

Passing $_GET or $_POST data to PHP script that is run with wget

I have the following line of PHP code which works great:
exec( 'wget http://www.mydomain.com/u1.php > /dev/null &' );
u1.php acts to do various types of maintenance on my server and the above command makes it happen in the background. No problems there.
But I need to pass variable data to u1.php before it's executed. I'd like to pass POST data preferably, but could accommodate GET or SESSION data if POST isn't an option. Basically the type of data being passed is user-specific and will vary depending on who is logged in to the site and triggering the above code. I've tried adding the GET data to the end of the URL and that didn't work.
So how else might I be able to send the data to u1.php? POST data preferred, SESSION data would work as well (but I tried this and it didn't pick up the logged in user's session data). GET would be a last resort.
Thanks!
To do it the way you have you would do this, probably using http_build_query
exec("wget --post-data 'a=b&c=d' http://www.mydomain.com/u1.php > /dev/null &");
However, I would be curious to know why you are choosing to use wget over cURL or, if the file is on the same server, calling it directly. It seems a bit clumsy to use wget for this.
Why dont you use cURL (if it's an option)? You can pass POST data very easy.
curl -d "your=postdata&more=postdata" http://www.mydomain.com/u1.php
Why not use the cURL implementation directly?
$c = curl_init('http://www.mydomain.com/u1.php');
curl_setopt($c, CURL_POSTFIELDS, $post_data);
curl_exec($c);
EDIT: To submit $post_data, you construct a string like a GET query string:
$vData = array(
'foo' => 'bar',
'zoid' => 'frob',
'slursh' => 'yargh',
);
$post_data = array();
foreach ($vData as $k => $v)
{
$post_data[] = urlencode($k) . '=' . urlencode($v);
}
$post_data = implode('&', $post_data);

Categories