I'm attempting to send results from a drupal webform through a cURL POST to a third party. My cURL function is not working, and I'm struggling to find my error. I have never used cURL before, so I'm not really sure how it works, or really even what it does.
From what I can tell, I'm piecing together the URL to be sent correctly, the send is just failing.
<?php
module_load_include('inc','webform','includes/webform.submissions');
$uri = $_SERVER[REQUEST_URI];
$sid = substr($uri, 20);
$submission = webform_get_submissions(array('sid' => $sid));
$nid = $submission[$sid]->nid;
$sql = db_select('webform_submitted_data', 'w');
$sql->fields('w', array('sid','cid','data'))
->condition('sid', $sid)
->condition('cid', array(1,2,3,4,5,6,7,8),'IN');
$results = $sql->execute();
$post = NULL;
$url = urlencode('http://ulm.datamark.com/services/lead_submission&client_code=DAV4516&source_code=DAVNCU');
foreach($results as $result)
{
if ($result->cid == 1) {
$post .= "first_name=" . urlencode($result->data);
} else if ($result->cid == 2) {
$post .= "&last_name=" . urlencode($result->data);
} else if ($result->cid == 3) {
$post .= "&email=" . urlencode($result->data);
} else if ($result->cid == 4) {
$post .= "&phone=" . urlencode($result->data);
} else if ($result->cid == 5) {
$who = $result->data;
} else if ($result->cid == 6) {
$post .= "&phone2=" . urlencode($result->data);
} else if ($result->cid == 8) {
$post .= "&comments=" . urlencode($result->data);
}
}
dsm($who);
dsm($url.$post);
if ($who == "fs")
{
$defaults = array(
CURLOPT_POST => 1,
CURLOPT_HEADER => 0,
CURLOPT_URL => $url,
CURLOPT_FRESH_CONNECT => 1,
CURLOPT_RETURNTRANSFER => 1,
CURLOPT_FORBID_REUSE => 1,
CURLOPT_TIMEOUT => 4,
CURLOPT_POSTFIELDS => http_build_query($post)
);
$ch = curl_init();
curl_setopt_array($ch, ($defaults));
if( ! $result = curl_exec($ch))
{
echo "Something went wrong";
trigger_error(curl_error($ch));
}
curl_close($ch);
?>
My eyes see a couple issues:
Do not urlencode the URL itself. That function is for data you are passing in the Query portion of the url (the part after ?)
It looks like you are missing the ? in your url.
I think you have some logical issues in your assembly of the Post data. First, you are encoding all of $result->data for every post field. You likely want to include only one field at a time. Second, you are passing a string into http_build_query(), which expects either an array or an object. Perhaps you can refactor to use $post as an array, which might make it easier to debug. Read the docs for cURL and http_build_query to see what everything expects and does. For example, the cURL extension can do a lot of work for you if you pass an array into curl_setopt for CURLOPT_POSTFIELDS.
Related
I'm new to php oop and I wanted to send the variable value from one function to another in a different page. So, currently I have this one function in one page that I want to send the data to the other function in a different page. Is that even possible perhaps?
Here's the first function in sendData.php
public function main($data) {
$settings = new Settings();
$hash_code = md5('standard' . '10068' . '08f94110d5697a2497511594c31704d0' .'3.00');
$std_post = array(
'apitype'=>'standard', //fix value
'apiid'=>'10068', //your api id from ibill
'apiorderid'=>'OPC0001#00000282', //your order id
'apihashcode'=>$hash_code, //generate hash code as above
'apiamount'=>'3.00', //your customer transaction amount
'apiemail'=>'alif4arsenal97#gmail.com'); //your customer email
$callbackJSON = json_encode($std_post);
$url = 'https://ibill.my/merchant/?ng=callback_api'; //link need to send data
$ch = curl_init($url); // where to post
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_POSTFIELDS, $callbackJSON);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$headers = array();
$headers[] = "Cache-Control: no-cache";
$headers[] = "Content-Type: application/json";
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
$results = curl_exec($ch);
if (curl_errno($ch)) {
echo 'Error:' . curl_error($ch);
}
curl_close($ch);
//echo $results;
$objJSON = json_decode($results); //decode json result
//should return 'SUCCESS'
$callback_status = $objJSON->{'callback_status'}; //callback Status
$message = $objJSON->{'message'}; //callback Message
//Refer on statuspage.php
$std_status_code = $objJSON->{'std_status_code'}; //payment status code
$std_status = $objJSON->{'std_status'}; //payment status
$std_order_id = $objJSON->{'std_order_id'}; //your order id
$std_purchase_code = $objJSON->{'std_purchase_code'}; //ibill transaction id
$std_amount = $objJSON->{'std_amount'}; //transaction amount
$std_datepaid = $objJSON->{'std_datepaid'}; //transaction date time
//Hash code for security
$std_hash_code = $objJSON->{'std_hash_code'}; //Hash code
$hash_code = md5('08f94110d5697a2497511594c31704d0'.'10068'.$std_order_id.$std_amount); //hash code format
$data = [
'callback_status' => $callback_status,
'message' => $message,
'std_status_code' => $std_status_code,
'std_status' => $std_status,
'std_order_id' => $std_order_id,
'std_purchase_code' => $std_purchase_code,
'std_amount' => $std_amount,
'std_datepaid' => $std_datepaid,
'std_hash_code' => $std_hash_code,
'hash_code' => $hash_code
];
processPayment($data);
}
Here's the second function in a different that I wanted the data in the first page to be send to which is test.php
public function processPayment($data)
{
if (!isset($data['std_status_code'])) return false;
if (!isset($data['std_hash_code'])) return false;
$settings = new Settings();
$sale_id = (int) substr($data['std_order_id'], 8);
$sale = Sales::get($sale_id);
if (empty($sale)) return false;
if ($sale['status'] == 1) return $sale;
if ($sale['payment_method'] !== 'ibill' || $sale['status'] != 0) return false;
$sale_uid = $sale['uid'];
$sale_method = $sale['method'];
$paid_amount = bcadd($sale['total_amount'], $sale['handling_charge'], 2);
// Verify the data integrity sent by iBill
$hash = md5($settings->ibill_secret_key . $settings->ibill_merchant_id . $data['std_order_id'] . $data['std_amount']);
$payment_processor_status = -1;
$sale_status = 0;
// Check provided hash and status
if ($hash === $data['std_hash_code'] && $data['std_status_code'] == 00) {
$payment_processor_status = 1;
$sale_status = 1;
}
if ($sale_status === 0) {
if ($data['std_status_code'] != 00) {
$data['std_status'] = '<span style="color: red">' . $data['std_status'] . '</span>';
}
if ($data['std_hash_code'] !== $hash) {
$data['std_hash_code'] = '<span style="color: red">' . $data['std_hash_code'] . '</span>';
}
}
// Prepare updated sale data
$now = new DateTime();
$sale = [
'payment_processor_status' => $payment_processor_status,
'payment_processor_data' => $data,
'payment_time' => $now->format('g:i:s A'),
'payment_date' => $now->format('d-m-Y')
];
Sales::update($sale_id, $sale);
if ($sale_status === 1) {
Sales::confirmSale($sale_id, false);
}
return ['uid' => $sale_uid, 'method' => $sale_method];
}
Those functions are class methods, not only functions.
you can use them (or pass data from one to another) by creating instances of their classes. for example something like this:
class one {
public function f1($data) {
// do something
$instance = new two();
$instance->f2($data);
}
}
class two {
public function f2($data) {
// do something else
}
}
I hope it would work for you.
I have function that basically returns visitor's country code and another that gets the currency. While running XAMPP on Windows, the return values of the function gets echoed like expected.
On Linux (eOS Loki), I've manually installed the LAMPP stack (not running XAMPP), this time PHP won't echo the return values of the functions. The page would stop loading, with no errors.
page stops loading immediately
NB: nhazi.dev is localhost
Country code function
function get_ipinfo( $option )
{
$url = "http://ipinfo.io/" . $_SERVER['REMOTE_ADDR'] . "/json";
if($_SERVER['REMOTE_ADDR'] == '127.0.0.1') // I develop offline most times.
{
$url = "http://nhazi.dev/php_curl/json"; //Offline Debugging
}
$ch = curl_init($url);
curl_setopt_array($ch, array(
CURLOPT_RETURNTRANSFER => true
)
);
$data = json_decode( curl_exec($ch) ); // decodes json response
curl_close($ch);
// Return value based on option
if(! $option)
return $data;
if($option == 'ip')
return $data->ip;
if($option == 'city')
return $data->city;
if($option == 'region')
return $data->region;
if($option == 'country')
return $data->country;
if($option == 'location')
return $data->loc;
if($option == 'org')
return $data->org;
}
Currency code function
function get_currency( $countrycode )
{
$url = "http://country.io/currency.json";
if($_SERVER['REMOTE_ADDR'] == '127.0.0.1')
{
$url = "http://nhazi.dev/php_curl/currency"; //Offline Debugging
}
$ch = curl_init($url);
curl_setopt_array($ch, array(
CURLOPT_RETURNTRANSFER => true,
)
);
$currency = json_decode(curl_exec($ch));
// print_r($currency); // Debugging
curl_close($ch);
return $currency->$countrycode;
}
Function Implementation
<p>
<?php echo get_currency( get_ipinfo('country') ); ?>
</p>
Can anyone help with the following
I'm trying to make a JSON request to a RESTful API. The code below is kindly shared by Wes Furlong
The code seems to be able to decode to JSON fine but sends as a URL encoded string
<?php
function rest_helper($url, $params = null, $verb = 'GET', $format = 'json')
{
$cparams = array(
'http' => array(
'method' => $verb,
'ignore_errors' => true
)
);
if ($params !== null) {
$params = http_build_query($params);
if ($verb == 'POST') {
$cparams['http']['content'] = $params;
} else {
$url .= '?' . $params;
}
}
$context = stream_context_create($cparams);
$fp = fopen($url, 'rb', false, $context);
if (!$fp) {
$res = false;
} else {
// If you're trying to troubleshoot problems, try uncommenting the
// next two lines; it will show you the HTTP response headers across
// all the redirects:
// $meta = stream_get_meta_data($fp);
// var_dump($meta['wrapper_data']);
$res = stream_get_contents($fp);
}
if ($res === false) {
throw new Exception("$verb $url failed: $php_errormsg");
}
switch ($format) {
case 'json':
$r = json_decode($res);
if ($r === null) {
throw new Exception("failed to decode $res as json");
}
return $r;
case 'xml':
$r = simplexml_load_string($res);
if ($r === null) {
throw new Exception("failed to decode $res as xml");
}
return $r;
}
return $res;
}
I need to be able to:
Add a content type of application/json
Convert params to JSON
Can't use curl in this environment
The main thing is the content type -- currently defaults to urlencoded
Any tips or ideas appreciated - Thanks
Latest attempt
function restHelper($url, $params = null, $verb = 'GET', $format = 'json'){
$cparams = array(
'http' => array(
'method' => $verb,
'ignore_errors' => true,
'header' =>"Content-type: application/json \r\n"
)
);
if ($params !== 'None') {
$jparams = json_encode($params);
if ($verb == 'POST') {
$cparams['http']['content'] = $jparams;
} elseif ($verb =='PUT') {
$cparams['http']['content'] = $jparams;
} else {
$params = http_build_query($params);
$url .= '?' . $params;
}
}
Still not working -- API tests fine from REST IDE Seems to be from how the content type is working for JSON
In the end found a way of including CURL in scriptcase.
Here is what worked (prototype)
(Thanks Lorna Jane http://www.lornajane.net/posts/2011/posting-json-data-with-php-curl)
Thanks everyone that looked at this
$service_url = 'http://dev.eventplus.co.nz/api/logon';
$ch = curl_init($service_url);
$data = '[
{
"Header": {
"Username": "testapi#teamprema.co.nz",
"SessionId": "123"
}
},
{
"Config": {}
},
{
"Params": {"Query": {"Password": "test12345"}}
}
]';
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PUT");
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-Type: application/json',
'Content-Length: ' . strlen($data))
);
curl_setopt($ch, CURLOPT_POSTFIELDS,$data);
$response = curl_exec($ch);
if ($response === false) {
$info = curl_getinfo($ch);
curl_close($ch);
die('error occured during curl exec. Additioanl info: ' . var_export($info));
}
curl_close($ch);
print $response;
I'm using a PHP script (using cURL) to check whether:
The links in my database are correct (ie return HTTP status 200)
The links are in fact redirected and redirect to an appropriate/similar page (using the contents of the page )
The results of this are saved to a log file and emailed to me as an attachment.
This is all fine and working, however it is slow as all hell and half the time it times out and aborts itself early. Of note, I have about 16,000 links to check.
Was wondering how best to make this run quicker, and what I'm doing wrong?
Code below:
function echoappend ($file,$tobewritten) {
fwrite($file,$tobewritten);
echo $tobewritten;
}
error_reporting(E_ALL);
ini_set('display_errors', '1');
$filename=date('YmdHis') . "linkcheck.htm";
echo $filename;
$file = fopen($filename,"w+");
try {
$conn = new PDO('mysql:host=localhost;dbname=databasename',$un,$pw);
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
echo '<b>connected to db</b><br /><br />';
$sitearray = array("medical.posterous","ebm.posterous","behavenet","guidance.nice","www.rch","emedicine","www.chw","www.rxlist","www.cks.nhs.uk");
foreach ($sitearray as $key => $value) {
$site=$value;
echoappend ($file, "<h1>" . $site . "</h1>");
$q="SELECT * FROM link WHERE url LIKE :site";
$stmt = $conn->prepare($q);
$stmt->execute(array(':site' => 'http://' . $site . '%'));
$result = $stmt->fetchAll();
$totallinks = 0;
$workinglinks = 0;
foreach($result as $row)
{
$ch = curl_init();
$originalurl = $row['url'];
curl_setopt($ch, CURLOPT_URL, $originalurl);
curl_setopt($ch, CURLOPT_HEADER, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_NOBODY, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false);
$output = curl_exec($ch);
if ($output === FALSE) {
echo "cURL Error: " . curl_error($ch);
}
$urlinfo = curl_getinfo($ch);
if ($urlinfo['http_code'] == 200)
{
echoappend($file, $row['name'] . ": <b>working!</b><br />");
$workinglinks++;
}
else if ($urlinfo['http_code'] == 301 || 302)
{
$redirectch = curl_init();
curl_setopt($redirectch, CURLOPT_URL, $originalurl);
curl_setopt($redirectch, CURLOPT_HEADER, 1);
curl_setopt($redirectch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($redirectch, CURLOPT_NOBODY, false);
curl_setopt($redirectch, CURLOPT_FOLLOWLOCATION, true);
$redirectoutput = curl_exec($redirectch);
$doc = new DOMDocument();
#$doc->loadHTML($redirectoutput);
$nodes = $doc->getElementsByTagName('title');
$title = $nodes->item(0)->nodeValue;
echoappend ($file, $row['name'] . ": <b>redirect ... </b>" . $title . " ... ");
if (strpos(strtolower($title),strtolower($row['name']))===false) {
echoappend ($file, "FAIL<br />");
}
else {
$header = curl_getinfo($redirectch);
echoappend ($file, $header['url']);
echoappend ($file, "SUCCESS<br />");
}
curl_close($redirectch);
}
else
{
echoappend ($file, $row['name'] . ": <b>FAIL code</b>" . $urlinfo['http_code'] . "<br />");
}
curl_close($ch);
$totallinks++;
}
echoappend ($file, '<br />');
echoappend ($file, $site . ": " . $workinglinks . "/" . $totallinks . " links working. <br /><br />");
}
$conn = null;
echo '<br /><b>connection closed</b><br /><br />';
} catch(PDOException $e) {
echo 'ERROR: ' . $e->getMessage();
}
Short answer is use the curl_multi_* methods to parallelize your requests.
The reason for the slowness is that web requests are comparatively slow. Sometimes VERY slow. Using the curl_multi_* functions lets you run multiple requests simultaneously.
One thing to be careful about is to limit the number of requests you run at once. In other words, don't run 16,000 requests at once. Maybe start at 16 and see how that goes.
The following example should help you get started:
<?php
//
// Fetch a bunch of URLs in parallel. Returns an array of results indexed
// by URL.
//
function fetch_urls($urls, $curl_options = array()) {
$curl_multi = curl_multi_init();
$handles = array();
$options = $curl_options + array(
CURLOPT_HEADER => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_NOBODY => true,
CURLOPT_FOLLOWLOCATION => true);
foreach($urls as $url) {
$handles[$url] = curl_init($url);
curl_setopt_array($handles[$url], $options);
curl_multi_add_handle($curl_multi, $handles[$url]);
}
$active = null;
do {
$status = curl_multi_exec($curl_multi, $active);
} while ($status == CURLM_CALL_MULTI_PERFORM);
while ($active && ($status == CURLM_OK)) {
if (curl_multi_select($curl_multi) != -1) {
do {
$status = curl_multi_exec($curl_multi, $active);
} while ($status == CURLM_CALL_MULTI_PERFORM);
}
}
if ($status != CURLM_OK) {
trigger_error("Curl multi read error $status\n", E_USER_WARNING);
}
$results = array();
foreach($handles as $url => $handle) {
$results[$url] = curl_getinfo($handle);
curl_multi_remove_handle($curl_multi, $handle);
curl_close($handle);
}
curl_multi_close($curl_multi);
return $results;
}
//
// The urls to test
//
$urls = array("http://google.com", "http://yahoo.com", "http://google.com/probably-bogus", "http://www.google.com.au");
//
// The number of URLs to test simultaneously
//
$request_limit = 2;
//
// Test URLs in batches
//
$redirected_urls = array();
for ($i = 0 ; $i < count($urls) ; $i += $request_limit) {
$results = fetch_urls(array_slice($urls, $i, $request_limit));
foreach($results as $url => $result) {
if ($result['http_code'] == 200) {
$status = "Worked!";
} else {
$status = "FAILED with {$result['http_code']}";
}
if ($result["redirect_count"] > 0) {
array_push($redirected_urls, $url);
echo "{$url}: ${status}\n";
} else {
echo "{$url}: redirected to {$result['url']} and {$status}\n";
}
}
}
//
// Handle redirected URLs
//
echo "Processing redirected URLs...\n";
for ($i = 0 ; $i < count($redirected_urls) ; $i += $request_limit) {
$results = fetch_urls(array_slice($redirected_urls, $i, $request_limit), array(CURLOPT_FOLLOWLOCATION => false));
foreach($results as $url => $result) {
if ($result['http_code'] == 301) {
echo "{$url} permanently redirected to {$result['url']}\n";
} else if ($result['http_code'] == 302) {
echo "{$url} termporarily redirected to {$result['url']}\n";
} else {
echo "{$url}: FAILED with {$result['http_code']}\n";
}
}
}
The above code processes a list of URLs in batches. It works in two passes. In the first pass, each request is configured to follow redirects and simply reports whether each URL ultimately lead to a successful request, or a failure.
The second pass processes any redirected URLs detected in the first pass and reports whether the redirect was a permanent redirection (meaning you can update your database with the new URL), or temporary (meaning you should NOT update your database).
NOTE:
In your original code, you have the following line, which will not work the way you expect it to:
else if ($urlinfo['http_code'] == 301 || 302)
The expression will ALWAYS return TRUE. The correct expression is:
else if ($urlinfo['http_code'] == 301 || $urlinfo['http_code'] == 302)
Also, put
set_time_limit(0);
at the top of your script to stop it aborting when it hits 30 seconds.
So the gist is that I need to post XML data query to a gateway page to receive a XML response which O parse later, there can be anywhere from 3-60 queries to this web service, I unfortunately have to run a simple loop right now and do them one at a time. On the response side, I will only need 1 (or a max of 5) of the lines in the response, line 2 is the first line that I need containing image data. So I'd like the ability to select which lines I am reading in if at all possible.
I created a simple "Read in" function as I said out of a basic for loop, here's the code that I am currently using and would like to revise.
$part1 = 'XML Beginning'; $part2 = XML End';
$posts = array( 0 => 'SC-010052214', 1 => 'SC-000032972', 2 => 'SC-012535460', 3 => 'SC-011257289', 4 => 'SC-010134078' );
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'http://example.com/index.php');
curl_setopt($ch, CURLOPT_RETURNTRANSFER => 1);
curl_setopt ($ch, CURLOPT_POST, 1);
$count = count($posts);
for($i=0;$i<$count;$i++) {
curl_setopt ($ch, CURLOPT_POSTFIELDS, "payload=$part1{$posts[$i]}$part2");
$return[] = curl_exec ($ch);
}
curl_close ($ch);
print_r($return);
Restrictions: I cannot use ?post=$data0&post=$data1&post=$data3 unfortunately, so I need a better solution. Other than that, I'd like to see what kinds of improvements can be made here.
Maybe http://php.net/manual/en/function.curl-multi-init.php helps you
Because of limits in quick response,
<?php
function m_curl($input) {
// compile queries for usable locations
foreach($input['content'] as $pos=>$item) {
$query = '<childDetailQuery><request><query-replacement>';
$query .= "<item_number>{$item}</item_number>";
$query .= (isset($input['story']) && $input['story'] != NULL)
? "<story_type>".$input['story']."</story_type>"
: '<story_type>SHORT</story_type>';
$query .= (isset($input['party']) && $input['party'] != NULL)
? "<party_number>".$input['party']."</party_number>"
: '';
$query .= "</query-replacement><latency-tolerance>NONE</latency-tolerance>";
$query .= '</request></childDetailQuery>';
$queries[] = $query;
unset($query);
}
// make sure the rolling window isn't greater than the # of urls
$limit = 10;
$limit = (sizeof($queries) < $limit) ? sizeof($queries) : $limit;
$master = curl_multi_init();
$curl_arr = array();
// add additional curl options here
$std_options = array(
CURLOPT_RETURNTRANSFER => 1,
CURLOPT_FOLLOWLOCATION => 1,
CURLOPT_MAXREDIRS => 0,
);
$options = ($coptions) ? ($std_options + $coptions) : $std_options;
echo $input['location'];
// start the first batch of requests
for ($i = 0; $i < $limit; $i++) {
$ch = curl_init();
$options[CURLOPT_POSTFIELDS] = "payload=".$queries[$i];
curl_setopt_array($ch,$options);
curl_multi_add_handle($master, $ch);
}
do {
while(($execrun = curl_multi_exec($master, $running)) == CURLM_CALL_MULTI_PERFORM);
if($execrun != CURLM_OK) {
echo 'Curl Error'; break;
}
// a request was just completed -- find out which one
while($done = curl_multi_info_read($master)) {
$info = curl_getinfo($done['handle']);
if ($info['http_code'] == 200) {
$output = curl_multi_getcontent($done['handle']);
// request successful. process output using the callback function.
parse_returns($output);
// start a new request (it's important to do this before removing the old one)
$ch = curl_init();
$options[CURLOPT_POSTFIELDS] = "payload=".$queries[$i++]; // increment i
curl_setopt_array($ch,$options);
curl_multi_add_handle($master, $ch);
// remove the curl handle that just completed
curl_multi_remove_handle($master, $done['handle']);
} else {
echo 'Failed on:'; var_dump($info);
echo 'With options:'; var_dump($options);
// request failed. add error handling.
}
}
} while ($running);
curl_multi_close($master);
return false;
}
function parse_returns($data) {
print_r($data);
}
// set query numbers
$data = array(
0 => 'SC-010052214',
1 => 'SC-000032972',
2 => 'SC-012535460',
3 => 'SC-011257289',
4 => 'SC-010134078'
);
// set options array
$options = array(
'location' => 'http://ibudev.wvus.org/websvc/actions/wvsMessageRouter.php',
'readline' => 2,
'coptions' => NULL,
'content' => $data,
'story' => 'FULL',
'party' => NULL,
);
m_curl($options);
?>