CakePHP REST API multipart file with json in one request - php

I have problem with CakePHP request handling…
I wrote an REST API to post some data and files and use multipart/form-data when want to send data.
When sending POST request(Multipart/form-data and send data as json),need to convert $this->request->data from json string to Array:
I wrote below code to convert json data to Array in beforeFilter of my controller:
$parser = function ($data) {
return json_decode($this->request->data,true);
};
$this->RequestHandler->addInputType("file", array($parser));
This is work fine and when I get $this->request->data in controller, JSON data successfully converted to Array,
But If I send request with file, this error happen:
Argument 1 passed to Hash::insert() must be of the type array, string given, called in /home/besepari/public_html/android/lib/Cake/Network/CakeRequest.php on line 401 and defined …
After research on codes,I find the problem but I couldn’t find a way to fix that.I think the error was generated because conversion of $data from json to array(in beforeFilter) happens after of this event so json string passed to Hash::insert() and make the error.need a way to convert json string of $data before of Hash::insert() execution.
Finally I found a way to fix this,but my approach maybe isn't good solution.Because I changed the core of cakephp class.
For fix the bug, replace cakeRequest.php _processFileData() method with this:
protected function _processFileData($path, $data, $field) {
//Fix bug of hash::insert string given(because in json multipart,$this->data is string and made a bug)
//check if string is json,parse it and save it to $this->data
if(!is_array($this->data)){
$parsedData=json_decode($this->data,true);
if (json_last_error() === JSON_ERROR_NONE) {
// JSON is valid
$this->data=$parsedData;
}
}
foreach ($data as $key => $fields) {
$newPath = $key;
if (strlen($path) > 0) {
$newPath = $path . '.' . $key;
}
if (is_array($fields)) {
$this->_processFileData($newPath, $fields, $field);
} else {
$newPath .= '.' . $field;
$this->data = Hash::insert($this->data, $newPath, $fields);
}
}
}
Thanks,
I use cakephp 2
sorry for bad English.

Related

How to return encoded json with json object in json codeigniter rest server

I am using the codeigniter rest by phil sturgeon.
I want to return a JSON object that contains another JSON object within.
My code looks like this
function volunteer_get()
{
if(!$this->get('id'))
{
$this->response(NULL, 400);
}
$this->load->model('user/users_model');
$user = $this->users_model->get( $this->get('id') );
$address = $this->address_model->getAddress( $this->get('id') );
$user->address = $address;
$userJson = json_encode($user);
var_dump($userJson);
/*if($user && $user->auth_level == 1)
{
$this->response($userJson, 200); // 200 being the HTTP response code
}
else
{
$this->response(NULL, 404);
}*/
}
It is not showing any result... If i do this without adding the php object in the other php object, it shows me the json!
D:\wamp\www\codeigniter\application\controllers\api\Users.php:37:string '{"user_id":"1","username":"abc","email":"abc","auth_level":"1","banned":null,"passwd":"abcdefg","passwd_recovery_code":"abcdefg","passwd_recovery_date":"2017-06-12 18:50:31","passwd_modified_at":"2016-11-18 21:20:30","last_login":"2017-08-30 15:10:36","created_at":"2016-09-02 12:01:46","modified_at":"2017-08-30 15:22:45","first_name":"aze","family_name":"'... (length=1354)
In general, you need to check whether you got a JSON object (usually a PHP dictionary or object) or a JSON representation (a string).
You can not add a string to another string. And if you add a string to a dictionary or object, it won't be properly encoded as a JSON sub-object because it is, well, a string.
So if you have a representation, you have to decode it first:
// Here, $dataOne is a string, and $dataTwo is too.
// we decode to array rather than to object (see manual for json_encode)
$dataOneJSON = json_decode($dataOne, true);
$dataTwoJSON = json_decode($dataTwo, true);
$dataOneJSON['two'] = $dataTwoJSON;
$result = json_encode($dataOneJSON);
$this->response($result, 200);

Validating HTTP Response Codes in PHPUnit

I am writing unit tests for several methods which return HTTP response codes. I cannot find a way to assert an HTTP response code. Perhaps I am missing something obvious, or I am misunderstanding something about PHPUnit.
I am using PHPUnit 4.5 stable.
Relevant part of class Message:
public function validate() {
// Decode JSON to array.
if (!$json = json_decode($this->read(), TRUE)) {
return http_response_code(415);
}
return $json;
}
// Abstracted file_get_contents a bit to facilitate unit testing.
public $_file_input = 'php://input';
public function read() {
return file_get_contents($this->_file_input);
}
Unit test:
// Load invalid JSON file and verify that validate() fails.
public function testValidateWhenInvalid() {
$stub1 = $this->getMockForAbstractClass('Message');
$path = __DIR__ . '/testDataMalformed.json';
$stub1->_file_input = $path;
$result = $stub1->validate();
// At this point, we have decoded the JSON file inside validate() and have expected it to fail.
// Validate that the return value from HTTP 415.
$this->assertEquals('415', $result);
}
PHPUnit returns:
1) MessageTest::testValidateWhenInvalid
Failed asserting that 'true' matches expected '415'.
I'm unsure why $result is returning 'true' . . . especially as a string value. Also unsure what my 'expected' argument ought to be.
According to the docs you can call the http_response_code() method with no parameters to receive the current response code.
<?php
http_response_code(401);
echo http_response_code(); //Output: 401
?>
Therefore your test should look like:
public function testValidateWhenInvalid() {
$stub1 = $this->getMockForAbstractClass('Message');
$path = __DIR__ . '/testDataMalformed.json';
$stub1->_file_input = $path;
$result = $stub1->validate();
// At this point, we have decoded the JSON file inside validate() and have expected it to fail.
// Validate that the return value from HTTP 415.
$this->assertEquals(415, http_response_code()); //Note you will get an int for the return value, not a string
}

Zend 2 REST Client Post Method sending header parameters also

In the Zend Framework 2, using REST Client using the POST method, the post URL has the query string,
As normal in postman when the request is post, the post content i have set
{"authToken":"11111111111111"} and post, status success.
when i get this value using GET method i have get the response, {"authToken":"11111111111111"}
which is correct.
when i run this through, php zend 2 using below method,
protected function genericSendRequest($url, $rawJsonData = NULL, $param = array()){
$response = '';
if(!empty($param)) {
$url .= '?' . http_build_query($param);
}
$client = $this->getHttpClient();
$client->setUri($url);
$client->setMethod('POST');
if($rawJsonData != null) {
$client->setRawBody(json_encode($rawJsonData));
}
$response = $client->send();
if ($response->isSuccess()) {
return $response->getContent();
}
return NULL;
}
Request Input,
$rawJsonData = array("authToken"=>"11111111111111");
$param = array("id"=>"9e770c9f71b4ef1b4ae85c58b0be4280253f9a2e");
Response i got,
id=9e770c9f71b4ef1b4ae85c58b0be4280253f9a2e&%7B%22authToken%22%3A%2211111111111111%22%7D=
This look like a URL query string,
i need the the response {"authToken":"11111111111111"}
ie. I need to get what i have post but i am getting post + query string,
query string is additionally posting to the request, that so its getting in the response,
how should avoid posting this querying string.
what the change needed in my code.?
Any help much appreciated.
Thanks in advance.
You question isn't very clear, but assuming you want to POST JSON data rather than form encoded data, you want:
if ($rawJsonData != null) {
$client->setRawBody(json_encode($rawJsonData));
}
Also, you could rewrite the query string part of your function to just:
if (!empty($param)) {
$uri .= '?' . http_build_query($param);
}

API Request $_POST returning empty array

I'm using Zurmo and trying to create a new account using REST API. I followed this documentation precisely: http://zurmo.org/wiki/rest-api-specification-accounts to pass the required parameters as json array.
This is my php code:
public function actionCreateOrUpdate()
{
$params=$_POST;
$modelClassName=$this->getModelName();
foreach ($params as $param)
{
if (!isset($param))
{
$message = Zurmo::t('ZurmoModule', 'Please provide data.');
throw new ApiException($message);
}
$r=$this->GetParam($param);
$res= array('status' => 'SUCCESS', 'data' => array($r));
print_r(json_encode($res,true));
}
}
function GetParam ($param){
$modelClassName=$this->getModelName();
if (isset($param['mobile_id'] ) && !$param['mobile_id']=='' &&!$param['mobile_id']==null)
{ $id=$param['mobile_id'];
$params=array();
foreach ($param as $k => $v) {
if(!($k=='mobile_id')) {
$params[$k] = $v;}
}
if ($params=null){$message = Zurmo::t('ZurmoModule', 'Please provide data.');
throw new ApiException($message);}
$tableName = $modelClassName::getTableName();
$beans = ZurmoRedBean::find($tableName, "mobile_id = '$id'");
if (count($beans) > 0)
{
$result = $this->processUpdate($id, $params);
}else{
$result = $this->processCreate($params,$id);
}
}
return $result;
}
The problem is that the $_POST method is returning an empty array. While debugging I tried to use print_r($_POST) and it also returned an empty array. I also tried to pass parameters as plain text and got the same result. I tried $_GET method and it worked. I think the problem is in the $_POST method, maybe I need to change something in my .php files. Any ideas please?
You should first hit the api with static data, to check if it works fine, then try to integrate php within that static data. You will need to read the documentation for which action accepts which format, and which method is supported(GET OR POST). Then try die(); , before sending if the array formed is as per the documentation.
I had similar issue when creating Account using REST API from java client. The problem was I did not send the proper POST request.
Another symptom also was on server side print_r(file_get_contents("php://input"),true); php code returned the correct request data.
Specifically the root cause was:
The Content-Type HTTP header was not "application/x-www-form-urlencoded"
The value field value in POST request was not properly encoded ( I used java.net.URLEncoder.encode method to overcome this)
After fixing these it worked.

Post 1:N (one customer many phonenumbers) JSON Array to android and parse it in PHP

I want to create a more complex JSON Array where a customer (which has a name) has many phonenumbers so that i can parse it in PHP and i need your help.
i.e.:
public Class ContactVO
{
public String diplayname;
public ArrayList<PhoneVO> phonenumbers = new ArrayList<PhoneVO>();
}
public Class PhoneVO
{
public String number;
}
Can s.o. give me an example how to create the above 1:N structure as JSON Array and how to parse it via PHP?
I put everything in a ArrayList and added the GSON library to may project.
The result is:
[
{"contact_id":"1","displayname":"Bjyyyyy","phonenumbers":[{"number":"066-6228"}]},
{"contact_id":"2","displayname":"Rainer Unsinn","phonenumbers":[{"number":"(066) 214-52"}]},
{"contact_id":"3","displayname":"Dieter karpenstein","phonenumbers":[{"number":"06621716669"}]},
{"contact_id":"4","displayname":"Sido","phonenumbers":[{"number":"(085) 011-1555"}]},
{"contact_id":"5","displayname":"Jochen Müller","phonenumbers":[{"number":"01773313261"}]}
]
How should the receiving PHP File lookslike to parse that?
Are you just looking for the json_decode function?
$fromPost = $_POST['contact'];
$object = json_decode($fromPost, true); // Read the doc to decide whether you want the "true" or not
var_dump($object);
Edit:
You could have something like that (not tested)
$string = '[
{"contact_id":"1","displayname":"Bjyyyyy","phonenumbers":[{"number":"066-6228"}]},
{"contact_id":"2","displayname":"Rainer Unsinn","phonenumbers":[{"number":"(066) 214-52"}]},
{"contact_id":"3","displayname":"Dieter karpenstein","phonenumbers":[{"number":"06621716669"}]},
{"contact_id":"4","displayname":"Sido","phonenumbers":[{"number":"(085) 011-1555"}]},
{"contact_id":"5","displayname":"Jochen Müller","phonenumbers":[{"number":"01773313261"}]}
]';
$decoded = json_decode($string);
foreach($decoded as $person) {
echo $person['displayname'] . "\n";
foreach($person['phonenumbers'] as $phone) {
echo $phone['number'] . "\n";
}
}

Categories