I'm tasked with Posting to an API that only accepts JSON. I am using PHP's CURL to accomplish this.
I have posted to API's before with no issue, but never with JSON, something I am not familiar with, I have tried to research this on my own and solve the problem, but I'm not having any luck.
When talking with someone at the company I am trying to post to, I was told that my server is hitting their server, the only thing wrong is the body of my post is not properly formatted JSON.. (no one at this company knows php :( so no help there)
Here is my code:
$jarr = array("ProviderID" => "L005A", "FirstName" => $first,
"LastName" => $last, "PhoneNumber" => $PhoneNumber,
"PhoneNumberType" => $PhoneNumberType);
$content = json_encode($jarr);
$curl_handle = curl_init("URL Im posting to");
curl_setopt($curl_handle, CURLOPT_HTTPHEADER, array(
'Accept: application/json;charset=utf-8',
'Content-Type: application/json;charset=utf-8',
'Expect: 100-continue',
'Connection: Keep-Alive'));
curl_setopt($curl_handle, CURLOPT_HEADER, 1);
curl_setopt($curl_handle, CURLOPT_POST, 0);
curl_setopt($curl_handle, CURLOPT_POSTFIELDS, $content);
curl_setopt($curl_handle, CURLOPT_FOLLOWLOCATION, 0);
curl_setopt($curl_handle, CURLOPT_RETURNTRANSFER, 1);
$first = curl_exec($curl_handle);
curl_close($curl_handle);
echo "Result ";
echo $first;
From the documentation I was given, the only parameters I must follow are:
Method: Post
Headers:
Accept: application/json;charset=utf-8
Content-Type: application/json;charset=utf-8
Expect: 100-continue
Connection: Keep-Alive
Currently, when I execute the script, I get a return of:
Result HTTP/1.1 100 Continue HTTP/1.1 400 Bad Request Cache-Control:
no-cache Pragma: no-cache Content-Type: application/json;
charset=utf-8 Expires: -1 Server: Microsoft-IIS/7.5 X-AspNet-Version:
4.0.30319 X-Powered-By: ASP.NET Date: Thu, 01 Nov 2012 15:43:18 GMT Content-Length: 26 {"record.ProviderID":[""]}
So the 400 error is caused because my body is not properly formatted. My question, how would I format the data I need to send in proper JSON format?
From what I have read, this code should do it, but it does not:
$jarr = array("ProviderID" => "L005A", "FirstName" => $first,
"LastName" => $last, "PhoneNumber" => $PhoneNumber,
"PhoneNumberType" => $PhoneNumberType);
$content = json_encode($jarr);
I faced the same problem. After debugging, found out that while sending JSON string, not quoting or double quoting the Integer values were the culprit. You need to send double quoted integer values as a string.
Eg:
{"PhoneNumber":9876543210}
or
{"PhoneNumber":"9876543210"}
will not work.
but
{"PhoneNumber":"N_9876543210"}
will work.
Will update as soon as I figure it out what exactly is the root cause of this problem. If someone knows, please update soon.
Edit: The problem solved by URL Encoding. I hope it solves in your case also.
Related
I'm trying to access this website natura.com.br to get info about some products, I'm trying to make a request the same way I do in the browser but I receive Access denied.
<?php
$url = "https://www.natura.com.br/";
$curl = curl_init($url);
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
$headers = array(
"User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:89.0) Gecko/20100101 Firefox/89.0",
"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
"Accept-Language: pt-BR,pt;q=0.8,en-US;q=0.5,en;q=0.3",
"Connection: keep-alive",
"Cookie: dtPC=11$302937546_809h-vKVNUNMUJAHDKTQPPAHFQIMSCQPPRKILC-0e0; rxvt=1625712010903|1625710210903; _abck=141C18ABCC9C79DFA1F4D45EF108501A~-1~YAAQk9j2SGYWZX56AQAAtC1zgwbF2BpCRBBWxNKDpMPWjPEYtw7XLvfB2g+dxkZSpfXBRCTvbE4fZTzGxjqtGVa7tZqz9pWp/hYSf65phFg2VW06IioCwpy7tox8su7QlWIt3eZUeTFIJ5S7nRtSv3Te859lzghM7a2lLnZOjpjS5eYLrJzYzyKFsRdc8Kpgj+sGCZA9iKiMvfqtJlI5e+90UfUDDzTQB2sV2U5i2yavjB+GsgBZ1qcKIfmo41PYfXtS8efG+3C4F4cw3sePIjj4vQIex1pQdg3twIbyqAMsEClNaqbGJ29NVu/orK7dAJ7rteSqWvyMuMu9MCltlPoYaYYi/O0Uzv18AiK9hSMYYWod7U/IqUkfE/touhQz6OT0S2KPjG0wJVJ8dghA8LdDJFH4+Y3YX4+oDw==~0~-1~-1; dtCookie=v_4_srv_11_sn_44IDRCETVPHGS7OCQ5F7DV8IS6T6HDI3_perc_100000_ol_0_mul_1_app-3A2a1999229615da92_1_app-3A58ea22250e34b990_1_rcs-3Acss_0; rxVisitor=1625332161003TGNBC4CH08VFEACK6NT19CQ14GERSQEA; dtSa=-; dtLatC=6; RT="z=1&dm=www.natura.com.br&si=a6979d10-a558-4bb3-a962-ccb19999271b&ss=kqu5jycl&sl=0&tt=0"; JSESSIONID=IUGNrH_B8h7DHZlVAsWr38FYiZq_I13dabE1sdnURzTRvdlsps50!-405357702; verifyFirstRequest=true; ORDER_ID=%3B%20; ORDER_NUMBER=%3B%20; X-Oracle-BMC-LBS-Route=93a9c3aed1d29d32ea0391633407edd696daed8327da03a11a2ff120e313e9b656c62fd8a7c42ae86da5fb4c73ec2333f092dbf8c9611add8055dec1; undefined; GTMUtmTimestamp=1625702943894; GTMCampaignReferrer=https%3A%2F%2Fwww.google.com%2F; GTMCampaignLP=https%3A%2F%2Fwww.natura.com.br%2Fp%2Fdesodorante-Col%25C3%25B4nia-kaiak-urbe-masculino-100ml%2F34075%3Futm_content%3DSP_Resp_MCKaiak_2020_Kaiak_Urbe%26cnddefault%3Dtrue%26gclid%3DEAIaIQobChMIxrmerJfS8QIV7R-tBh01uwM5EAAYASAAEgIZU_D_BwE; _gcl_au=1.1.467484977.1625332166; _ga_15QCH7XEDY=GS1.1.1625874531.3.0.1625874531.60; _ga=GA1.3.1744316957.1625332166; GTMBrowserSessionEntranceTimestamp=1625332166546; GTMBrowserSessionEntranceLP=https%3A%2F%2Fwww.natura.com.br%2Facesso-consultor; GTMBrowserSessionEntranceReferrer=https%3A%2F%2Fwww.google.com%2F; GTMLastEntranceTimestamp=1625702945066; GTMLastEntranceLP=https%3A%2F%2Fwww.natura.com.br%2Fp%2Fdesodorante-Col%25C3%25B4nia-kaiak-urbe-masculino-100ml%2F34075%3Futm_content%3DSP_Resp_MCKaiak_2020_Kaiak_Urbe%26cnddefault%3Dtrue%26gclid%3DEAIaIQobChMIxrmerJfS8QIV7R-tBh01uwM5EAAYASAAEgIZU_D_BwE; GTMLastEntranceReferrer=https%3A%2F%2Fwww.google.com%2F; _fbp=fb.2.1625332167173.86579534; GTMUtmSource=google; GTMUtmMedium=cpc; GTMUtmCampaign=auto; GTMGclid=EAIaIQobChMIxrmerJfS8QIV7R-tBh01uwM5EAAYASAAEgIZU_D_BwE; _gcl_aw=GCL.1625702944.EAIaIQobChMIxrmerJfS8QIV7R-tBh01uwM5EAAYASAAEgIZU_D_BwE; _ttgclid=EAIaIQobChMIxrmerJfS8QIV7R-tBh01uwM5EAAYASAAEgIZU_D_BwE; _ttgclid=EAIaIQobChMIxrmerJfS8QIV7R-tBh01uwM5EAAYASAAEgIZU_D_BwE; __bid=4dbbd24a-fc0e-42aa-a664-43c865cae2ef; _gac_UA-35236522-3=1.1625703004.EAIaIQobChMIxrmerJfS8QIV7R-tBh01uwM5EAAYASAAEgIZU_D_BwE; cto_bundle=qVL1jF8yb3h2cW01cmFaUjF5S2VnMkdGcDEyNHdrWWM3ZXpZcFFIMkowdmZqOFZpNTE3VGIlMkJibkZZZXpMJTJGYXBqRElFT0FwdFRia3ZwQ1JZSzZ2ZEx1RSUyQnBXUW54MmM1S3UlMkY3WjlqenBXU1dDZFlRaTYlMkZucVdPM2c5MTJUcERYc2pLcEdyeURWQU9ieDhmaTR1WGJoN1FhaHR4Nm5MZWdJUUNmZUI0MkdNYk50VXpFRGg0Z2hUSlNxS25xZGFNVjJZTGpC; GTMVisitSession=1625702947208; GTMVisitPermanent=1625702947208; _uetvid=b67fe410df8011eb85947b37dce069f8; smeventsclear_d13b2682b72e42cc9203ee1f0a20b68d=true; personNumber=141692103; smCloseBounce=true",
"Upgrade-Insecure-Requests: 1",
);
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
$resp = curl_exec($curl);
curl_close($curl);
var_dump($resp);
?>
I get this HEADER when I do the request
"HTTP/1.1 403 Forbidden Server: AkamaiGHost Mime-Version: 1.0 Content-Type: text/html Content-Length: 271 Cache-Control: max-age=1800 Expires: Sat, 10 Jul 2021 21:35:46 GMT Date: Sat, 10 Jul 2021 21:05:46 GMT Connection: close Server-Timing: cdn-cache; desc=HIT Server-Timing: edge; dur=1 Timing-Allow-Origin: true Access-Control-Max-Age: 86400 Access-Control-Allow-Credentials: true Access-Control-Allow-Headers: * Access-Control-Allow-Methods: GET,POST,OPTIONS Access-Control-Allow-Origin: *
First of all, within "" PHP tries to convert variables to strings. So
$foo = "Hello, ";
echo "$foo World" . PHP_EOL;
would output
Hello, World
You are using "" and have the $-sign in your cookie (not to mention the fact that the cookie-string itself contains the "-sign). So PHP is not sending that "as-is" in the cookie but instead trying to find that variable and turn it into a string. If you don't want this behavior use single quotes ' instead.
So that could be your issue as long as the information in the cookie is valid and should allow you access.
Besides this it is hard to know what happens in the backend of natura.com.br to block your access. It could be any number of things. Do you need to login, do you have a valid session etc.
Instead of working with curl directly you could use Guzzle which is a great PHP based HTTP-Client that simplifies a lot of stuff. It can keep track of cookies and append them automatically etc.
Currently working with integrating a new e-commerce API (Swish) but having a bit of a struggle. I'm using PHP and cURL in my app to perform a test-connection to their Merchant Simulator. Code looks as follows:
$post = array(
"payeePaymentReference"=> "0123456789",
"callbackUrl"=> "https://myssldomain.com",
"payerAlias"=> "4671234768",
"payeeAlias"=> "1231181189",
"amount"=> "100",
"currency"=> "SEK",
"message"=> "Kingston USB Flash Drive 8 GB"
);
$ch = curl_init();
curl_setopt($ch,CURLOPT_RETURNTRANSFER, false);
curl_setopt($ch,CURLOPT_HEADER, true);
curl_setopt($ch,CURLOPT_URL, 'https://mss.swicpc.bankgirot.se/swish-cpcapi/api/v1/paymentrequests/');
curl_setopt($ch,CURLOPT_SSL_VERIFYPEER, true);
curl_setopt($ch,CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($ch,CURLOPT_POSTFIELDS, $post);
curl_setopt($ch,CURLOPT_SSLKEY, 'sslkey.key');
curl_setopt($ch,CURLOPT_SSLCERT, 'sslcert.crt');
curl_setopt($ch, CURLOPT_CAINFO, 'cainfo.crt');
$data = curl_exec($ch);
$error = curl_error($ch);
curl_close($ch);
var_dump($data);
Note: the callback-url in the post-array is different. I have a valid, SSL-domain set there as callback URL.
The response i get when proceeding with above code is this:
HTTP/1.1 415 Unsupported Media Type
Server: Apache-Coyote/1.1
Accept-Ranges: bytes
ETag: W/"0-1448896356000"
Last-Modified: Mon, 30 Nov 2015 15:12:36 GMT
Content-Type: text/html
Content-Length: 0
Date: Sun, 24 Jan 2016 21:07:00 GMT
The 3 parts of the SSL-certificate can be found at Swish's API site if you download the test-tool (Guide Testverktyg). Can anyone please tell me what i'm doing wrong?
Have you tried adding
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json'));
If you post an array directly to the POST, it will transfer as Content-Type: multipart/form-data; boundary=---------------------------- and that's why you are getting this unsupported media type error.
Use http_build_query over your array and you should be fine as it will send data as Content-Type: application/x-www-form-urlencoded
curl_setopt($ch,CURLOPT_POSTFIELDS, http_build_query($post));
Using php curl I am trying to connect to an api I have built. I am having trouble creating a custom header with curl well trying to dictate some header information such as Content-Type, Content-Length.
I am also struggling to understand how to properly send (post) a http-body full of json data.
Essentially what I am trying to do is have the header have the Content-Type, Content-Length, some custom fields like $api => "45234523452345", $hashedKey => "32413211234123".
Well sending a payload (an array json encoded or json encoded multidimensional arry) in the http-body.
Here is what I am trying to use right now.
public function mainRequest($url, $apiKey) {
$payload = array(
'test' => 'data'
);
$jsonPayload = urlencode(json_encode($payload));
$encyptedKey = $this->dataEncyptor->hashData($apiKey);
$header = array(
'Content-Type:' => 'application/json',
'Content-Length:' => strlen($jsonPayload),
'x-public' => $apiKey,
'x-hash' => $encyptedKey
);
$fp = fopen(dirname(__FILE__).'/errorlog.txt', 'w');
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_VERBOSE, true);
curl_setopt($ch, CURLOPT_STDERR, $fp);
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_POSTFIELDS, $jsonPayload);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
// curl_setopt($ch, CURLOPT_POST, 1);
$result = curl_exec($ch);
curl_close($ch);
return $result;
}
In my error log I get this:
* About to connect() to local.nslim.ca port 80 (#0)
* Trying 127.0.0.1...
* connected
* Connected to local.nslim.ca (127.0.0.1) port 80 (#0)
> POST /datacheck HTTP/1.1
Host: local.nslim.ca
Accept: */*
Content-Length: 29
Content-Type: application/x-www-form-urlencoded
* upload completely sent off: 29 out of 29 bytes
< HTTP/1.1 404 Not Found
< Date: Fri, 17 Oct 2014 03:05:43 GMT
< Server: Apache/2.2.25 (Unix) mod_ssl/2.2.25 OpenSSL/0.9.8za DAV/2 PHP/5.5.3
< X-Powered-By: PHP/5.5.3
< Content-Length: 514
< Content-Type: text/html
<
* Connection #0 to host local.nslim.ca left intact
* Closing connection #0
And outputted to the screen is:
HTTP/1.1 404 Not Found Date: Fri, 17 Oct 2014 03:06:07 GMT Server: Apache/2.2.25 (Unix) mod_ssl/2.2.25 OpenSSL/0.9.8za DAV/2 PHP/5.5.3 X-Powered-By: PHP/5.5.3 Content-Length: 514 Content-Type: text/html
404 Page Not Found
The page you are looking for could not be found. Check the address bar to ensure your URL is spelled correctly. If all else fails, you can visit our home page at the link below.
Visit the Home Page
Do the cURL setopt's need to be in any particular order?
Thanks for any help!
So the obvious question is, do you have the URL correct? 404 doesn't indicate an error on the page, rather that the page isn't there. Should it be datacheck.php?
Also, you are not sending your data as a standard web form so you will want to change the Content-Type header to 'text/json' and retrieve it in your script using php://input.
Edit: see also RAW POST using cURL in PHP
I would like to perform a PUT operation on a webservice using CURL. Let's assume that:
webservice url: http://stageapi.myprepaid.co.za/api/ConsumerRegisterRequest/cac52674-1711-e311-b4a8-00155d4905d3
municipality= NMBM
sgc= 12345
I've written the code below, but it outputs this error message: "ExceptionMessage":"Object reference not set to an instance of an object.". Any help would be so much appreciated. Thanks!
<?php
function sendJSONRequest($url, $data)
{
$data_string = json_encode($data);
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PUT");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data_string);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-Type: application/json',
'Accept: application/json',
'X-MP-Version: 10072013')
);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
ob_start();
$result = curl_exec($ch);
$info = curl_getinfo($ch);
if ($result === false || $info['http_code'] == 400) {
return $result;
} else {
return $result;
}
ob_end_clean();
curl_close($ch);
}
$mun = $_GET['municipality'];
$sgc = $_GET['sgc'];
$req = $_GET['req']; //cac52674-1711-e311-b4a8-00155d4905d3
//myPrepaid PUT URL
echo $mpurl = "http://stageapi.myprepaid.co.za/api/ConsumerRegisterRequest/$req";
// Set Variables
$data = array("Municipality" => "$mun", "SGC" => "$sgc");
//Get Response
echo $response = sendJSONRequest($mpurl, $data);
?>
I copied your code, but changed it so it pointed at a very basic HTTP server on my localhost. Your code is working correctly, and making the following request:
PUT /api/ConsumerRegisterRequest/cac52674-1711-e311-b4a8-00155d4905d3 HTTP/1.1
Host: localhost:9420
Content-Type: application/json
Accept: application/json
X-MP-Version: 10072013
Content-Length: 37
{"Municipality":"NMBM","SGC":"12345"}
The error message you're receiving is coming from the stageapi.myprepaid.co.za server. This is the full response when I point it back to them:
HTTP/1.1 500 Internal Server Error
Cache-Control: no-cache
Pragma: no-cache
Content-Type: application/json; charset=utf-8
Expires: -1
Server: Microsoft-IIS/8.0
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Date: Fri, 30 Aug 2013 04:30:41 GMT
Connection: close
Content-Length: 867
{"Message":"An error has occurred.","ExceptionMessage":"Object reference not set to an instance of an object.","ExceptionType":"System.NullReferenceException","StackTrace":" at MyPrepaidApi.Controllers.ConsumerRegisterRequestController.Put(CrmRegisterRequest value) in c:\\Workspace\\MyPrepaid\\Prepaid Vending System\\PrepaidCloud\\WebApi\\Controllers\\ConsumerRegisterRequestController.cs:line 190\r\n at lambda_method(Closure , Object , Object[] )\r\n at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.<>c__DisplayClass13.<GetExecutor>b__c(Object instance, Object[] methodParameters)\r\n at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.Execute(Object instance, Object[] arguments)\r\n at System.Threading.Tasks.TaskHelpers.RunSynchronously[TResult](Func`1 func, CancellationToken cancellationToken)"}
You may want to check out the API to make sure you're passing them the correct information. If you are, the problem could be on their end.
And while I realize this isn't part of your question and this is in development, please remember to sanitize any data from $_GET. :)
Try with:
curl_setopt($ch, CURLOPT_PUT, true);
I am not that experienced with cURL and I have spent a couple of days trying to sort this problem: I have an issue with cURL not appending the query string to my URL in the headers when I submit a POST request; hence no 'payload' is received by the server and I get returned an error status code by the service I'm accessing which indicated it didn't receive the appropriate data.
I think the POST should start with the full domain name, but I'm not sure. If I'm posting data, shouldn't Content-Length be '0' instead of what I am getting?
The outgoing header looks like this:
POST /rest/v1/oliver/groups/ORIGINNUMBER/member? HTTP/1.1
Accept: application/xml
Content-type: text/plain
User-Agent: Custom PHP Script
Host: campaign.oventus.com
Cookie: JSESSIONID=SECRETCOOKIE
Content-Length: 95
My php code looks like this:
$fields_string = "firstName=$fname&secondName=$sname&password=$pass&deviceAddress=$phonenumber¬es=testing";
$url = "http://campaign.oventus.com/rest/v1/ACCOUNTNAME/groups/ORIGINNUMBER/member?";
$header[] = "Accept: application/xml";
$header[] = "Content-type: text/plain";
$header[] = "User-Agent: Custom PHP Script";
$header[] = "Host: campaign.oventus.com";
$header[] = "Cookie: ".$cookie;
$cx = curl_init();
curl_setopt($cx, CURLOPT_URL,$url);
curl_setopt($cx, CURLOPT_POST, 5);
curl_setopt($cx, CURLOPT_POSTFIELDS,$fields_string);
curl_setopt($cx, CURLOPT_HTTPHEADER, $header);
curl_setopt($cx, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($cx, CURLOPT_SSL_VERIFYHOST, FALSE);
curl_setopt($cx, CURLOPT_RETURNTRANSFER, true);
curl_setopt($cx, CURLOPT_FOLLOWLOCATION, FALSE);
curl_setopt($cx, CURLOPT_TIMEOUT, 15);
curl_setopt($cx, CURLOPT_HEADER, 1);
curl_setopt($cx, CURLINFO_HEADER_OUT, TRUE);
$final = curl_exec($cx);
$errors = curl_error($cx);
$errornos = curl_errno($cx);
$headcut2 = explode ("n/xml", $final);
$headstring2 = $headcut2[0]."n/xml";
$xmlstring2 = $headcut2[1];
echo "<h2>Add to Group result: </h2>";
echo "<p>RAW header: <code>$final</code></p>";
//echo "<p>Response header: <code>".htmlentities($headstring2)."</code></p>";
echo "<p>XML response: <code>".htmlentities($xmlstring2)."</code></p>";
//echo "<p>".print_r($info)."</p>";
//echo "<p>CURL info: $info</p>";
//echo "<p>Curl error: $errors</p>";
echo "<p>Curl error num: $errornos</p>";
print "<pre>\n";
print_r(curl_getinfo($cx)); // get error info
print "</pre>\n";
curl_close($cx);
And the header returned by the server is this:
HTTP/1.1 200 OK Date: Fri, 26 Aug 2011 17:30:12 GMT
Server: Apache/2.2.17 (Unix) DAV/2 Content-Length: 144
X-Powered-By: Servlet/2.5 JSP/2.1 Cache-Control: no-store, no-cache
Vary: Accept-Encoding,User-Agent Pragma: no-cache
Content-Type: application/xml 202
With the returned XML:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<status xmlns="http://jaxb.rest.pageone.com" description="No Devices to add">202</status>
As far as I can tell, I'm definitely hitting the server, but it doesn't seem to receive the data I'm sending it..
Stumped. Hope someone can point me in the right direction!
Cheers,
Looks like your hitting the server, and likely the data is going to... I think the answer lies in 202:No Devices to add... which the REST interface documentation should explain (perhaps you're missing a required field?) {202 FYI means accepted but no processing was completed, could also mean the user exists}
By the way you should be escaping those arguments you're putting into the POST payload ($fname,$sname,$pass,$phonenumber)... otherwise a weird value (say name) could cause the post to act completely differently to the way you expected. You can do that using urlencode, or by instead building the POST string with http_build_query
<?php
$fields_string=http_build_query(array(
"firstName"=>$fname,
"secondName"=>$sname,
"password"=>$pass,
"deviceAddress"=>$phonenumber,
"notes"=>"testing"));
//...
?>