Unable to get input data sent from cross site domain - php

I am using laravel as backend and angujarjs as frontend to make an application. The frontend is sitting in another server, and therefore I have to deal with cross domain policy. I have enabled CORS, so I can "send" post request.
The problem is that when I am trying to get Input::all() in laravel, the request gets cancelled. (status shown 'cancelled' in Chrome network). But when I dont use Input, everything is OK.
//laravel
class SessionController extends BaseController {
protected $entity;
public function __construct(SessionEntity $entity)
{
$this->entity = $entity;
}
public function getLogin()
{
return Response::json('hello')->header('Access-Control-Allow-Origin', '*');
}
public function postLogin()
{
//$data = Input::all();
//return Response::json($data);
// $user = $entity->login($data);
// if($user)
// {
// return Response::json($user);
// } else {
// return Response::json($entity->errors(), 400);
// }
//the code below is OK (able to send response back) , but the code above is not, because I am using Input::all()
$data = array(
"email" => "324234",
"password" => "654321"
);
return Response::json($data);
}
}
//angularjs
.controller('LoginController', ['$scope', '$http', function($scope, $http) {
$scope.send = function(credential) {
$http({
method: 'POST',
url: 'http://localhost:8000/api/session/login',
data: credential,
headers: {
'Content-Type': 'application/json; charset=UTF-8'
}
})
.success(function(data, status, headers) {
console.log(data);
console.log(status);
console.log(headers);
});
};
}]);
Here's the headers to enable CORS
App::after(function($request, $response)
{
$response->headers->set('Access-Control-Allow-Origin', '*');
$response->headers->set('Access-Control-Allow-Methods', 'POST, GET, OPTIONS, PUT');
$response->headers->set('Access-Control-Allow-Headers', 'Content-Type');
$response->headers->set('Access-Control-Allow-Credentials', 'true');
$response->headers->set('Access-Control-Max-Age', '1728000');
$response->headers->set('Content-Type', 'application/json; charset=UTF-8');
return $response;
});
What did I miss??

I found it. I use namespace but didn't include 'use Input'.
silly me...
Also, I found that I have to explicitly set Content-Type to 'application/json' in order to receive data using Input::all() in laravel, otherwise I get no data.

For cross domain requests you must use jsonp instead json

Related

input->post and $_POST are empty in CodeIgniter API calling from Angular 4, what is the right way to make a post request in angular 4

This is the first time I'm making a post method request from Angular to CodeIgniter rest API.
postUsertask(Userid,TaskName)
{
let body ={
userid:Userid, taskname:TaskName
};
console.log(body);
return this.http.post("http://localhost/ci-abc/api/add_task",JSON.stringify(body) )
.map(res => res.json());
}
API method in codeigniter:
function add_task_post()
{
$obj=json_decode(file_get_contents('php://input'));
$taskname = $obj->taskname;
$userid = $obj->userid;
if (!$taskname || !$userid) {
$this->response("Enter taskname and userid to add", 400);
} else
$result = $this->todo_model->add_task($taskname, $userid);
if ($result === 0) {
$this->response("Task could not be added. Try again.", 404);
} else {
$this->response("success", 200);
}
}
Had to include to access the data
$obj=json_decode(file_get_contents('php://input'));
Because the $this->input->post and $_POST were empty and the data recieved from angular was an object so had to be accessed with -> notation. I am curious that this is not the right and ethical way to do this. Also when I didn't put JSON.stringify it gave me Cross Origin Request blocked error so that's why I put it. How should I make POST and PUT request in angular4 to rest API in CodeIgniter?
How do I get rid of CORS error which doesn't let me call the API method, if I can get rid of CORS error then I could also remove JSON.stringify which will send the data as it is and I believe the data should be accessed via input->post or $_POST.
EDIT 2:
These sort of errors while making POST PUT and DELETE API call.
Cross-Origin Request Blocked: The Same Origin Policy disallows reading
the remote resource at http://localhost/ci-abc/api/del_task?taskid=34.
(Reason: CORS preflight channel did not succeed)
EDIT (Perfect Solution):
Found out that the formdata object approach was deprecated so I just included a header in options and included in the API call http.post method which works fine and is much better solution.
constructor(public http:Http) {
let headers = new Headers();
headers.append('Content-Type', 'application/json');
let options = new RequestOptions({ headers: headers });}
createUser(userName)
{
let body = { username:userName};
return this.http.post("http://localhost/ci-abc/api/create_user",body,this.options)
.map(res => res.json());
}
Deprecated approach (Works but deprecated/not usual practice):
Took few hours but found the solution, I created body as a new formdata object, appended parameters to it as key and their values and it worked fine now I am retrieving through $this->input->post.
let body = new FormData;
body.append('userid', Userid);
body.append('taskname', TaskName);
console.log(body);
return this.http.post("http://localhost/ci-abc/api/add_task",body)
.map(res => res.json());
Using these headers in the constructor of my codeigniters API controller
header("Access-Control-Allow-Origin: *");
header('Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Access-Control-Allow-Origin');
header('Access-Control-Allow-Methods: POST, GET, OPTIONS, PUT, DELETE');
API method:
function add_task_post()
{
$userid = $this->input->post('userid');
$taskname = $this->input->post('taskname');
if (!$taskname || !$userid) {
$this->response("Enter taskname and userid to add", 400);
} else
$result = $this->todo_model->add_task($taskname, $userid);
if ($result === 0) {
$this->response("Task could not be added. Try again.", 404);
} else {
$this->response("success", 200);
}
}

Request blocked by CORS policy

I have an API built with PHP Slim Framework 3 and testing the API with Postman everything is working great but when I put the app on the server and tried to make an Ajax Call I've got this message:
Failed to load https://api.mydomain.net/usuario/autenticar?xAuthClienteID=2&xAuthChaveApi=3851b1ae73ca0ca6e3c24a0256a80ace&login=admin&senha=teste: Redirect from 'https://api.maydomain.net/usuario/autenticar?xAuthClienteID=2&xAuthChaveApi=3851b1ae73ca0ca6e3c24a0256a80ace&login=admin&senha=teste' to 'https://api.mydomain.net/404.html' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost' is therefore not allowed access.
I've looked up Slim docs on how to enable CORS on my server and applied it on the function I use to return JSON. It looks like this:
public function withCustomJson($meta = null, $data = null)
{
if (isset($data)) {
$finalResponse['data'] = $data;
}
$finalResponse['meta'] = array(
'status' => (isset($meta['status']) ? $meta['status'] : null),
'message' => (isset($meta['message']) ? mb_convert_encoding($meta['message'], "UTF-8", "auto") : null)
);
$response = $this->withBody(new Body(fopen('php://temp', 'r+')));
$response->body->write($json = json_encode($finalResponse));
// Ensure that the json encoding passed successfully
if ($json === false) {
throw new \RuntimeException(json_last_error_msg(), json_last_error());
}
//Allowing CORS as Slim docs states
$responseWithJson = $response->withHeader('Content-Type', 'application/json;charset=utf-8')
->withHeader('Access-Control-Allow-Origin', '*')
->withHeader('Access-Control-Allow-Headers', 'X-Requested-With, Content-Type, Accept, Origin, Authorization')
->withHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
if (isset($meta['codStatus'])) {
return $responseWithJson->withStatus($meta['codStatus']);
}
return $responseWithJson;
}
And here's what my Ajax call looks like:
<script type="text/javascript">
try {
$.ajax({
url: 'https://api.mydomain.net/usuario/autenticar',
type: 'GET',
dataType: 'json',
data: {
xAuthClienteID:'2',
xAuthChaveApi: '3851b1ae73ca0ca6e3c24a0256a80ace',
login: 'admin',
senha: 'teste'
},
ContentType: 'application/json',
success: function(response){
console.log(response);
},
error: function(err){
console.log(err);
}
});
}
catch(err) {
alert(err);
}
</script>
So, what am I doing wrong? Appreciate any help.

Cannot Recieve Request Parameter in Symfony2 Angular2

problem
i tried with $request->request->all() //var_dump output:array(0){}
symfony code
public function registerAction(Request $request) {
var_dump($request->request->all());die;
}
Angular2 service
export class UserRegistrationService {
constructor(private http: Http) { }
private headers = new Headers({'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'});
private insertdataUrl =
'http://localhost/abc/web/app_dev.php/api/v1/register-user';
/* create new user */
create(name: string): Promise<UserDetails> {
return this.http
.post(this.insertdataUrl, JSON.stringify({name: name}), {headers: this.headers})
.toPromise()
.then(res => res.json().data as UserDetails)
.catch(this.handleError);
}
FormData
{"name{"email":"abc#gmail.com","username":"abc","password":"","repeatpassword":""}}:
solution that works
$data = json_decode(file_get_contents('php://input'), true);
// able to get paramters //get,or //post
can anyone suggest why request doesn't print some values.
here im posting form from angular2.
Symfony uses different containers for Post and Get. Try this way.
# Post
$request->request->all()
# Get
$request->query->all()
solution that worked for me
i changed headers
from
private headers = new Headers({'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'});
To
private headers=new Headers({ 'Content-Type': 'application/json' });
now im able to recieve data.

Slim PHP v3 CSRF with ajax and the fetch API

i have set up the normal CSRF stuff etc and would work well, but then when i go and use ajax using the whatwg-fetch api (https://github.com/github/fetch)
Now all seem ok and all works well to what i have. BUT! Then I add the CSRF settings as below and it fails, all the time:
So, I have used the normal, but it fails and in the header I get the message: Failed CSRF check!
$app->add(new \Slim\Csrf\Guard);
But I wanted to add own message etc so have added the following, but still it does not pass.
$container['csrf'] = function ($c) {
$guard = new \Slim\Csrf\Guard;
$guard->setFailureCallable(function ($request, $response, $next) {
$request = $request->withAttribute("csrf_status", false);
return $next($request, $response);
});
return $guard;
};
$app->add($container->get('csrf'));
Then in my class i check it with:
if (false === $req->getAttribute('csrf_status')) {...}else{//all ok}
But what ever happens it always fails.
in my js i am adding the token details to the request like:
fetch('/post/url',{
method: 'POST',
headers: {
'X-CSRF-Token': {
'csrf_name':csrf_name,
'csrf_value':csrf_value
}
},
body: new FormData(theForm)
i have looked in the posted data etc and the form data is submitted including the csrf values etc. SO the require csrf data is being sent via the form as well as the header?
So how can I get the ajax functionality to work with the Slim CSRF, what am I missing?
Thanks in advance
I was also unable to get fetch to put the tokens into the body. I decided to extend the class so I could modify the __invoke method. I have added some code to pull the csrf from the headers.
in your dependencies now use this class.
$c['csrf'] = function ($c) {
return new \Foo\CSRF\Guard;
};
The extended class.
<?php
namespace MYOWN\CSRF;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\ResponseInterface;
/**
* CSRF protection middleware.
*/
class Guard extends \Slim\Csrf\Guard
{
public function __construct(
$prefix = 'csrf',
&$storage = null,
callable $failureCallable = null,
$storageLimit = 200,
$strength = 16,
$persistentTokenMode = false
) {
parent::__construct(
$prefix,
$storage,
$failureCallable,
$storageLimit,
$strength,
$persistentTokenMode);
}
public function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable $next)
{
$this->validateStorage();
// Validate POST, PUT, DELETE, PATCH requests
if (in_array($request->getMethod(), ['POST', 'PUT', 'DELETE', 'PATCH'])) {
$body = $request->getParsedBody();
$body = $body ? (array)$body : [];
$name = isset($body[$this->prefix . '_name']) ? $body[$this->prefix . '_name'] : false;
$value = isset($body[$this->prefix . '_value']) ? $body[$this->prefix . '_value'] : false;
if (!empty($csrfTokens = $request->getHeader('x-csrf-token'))) {
$csrfTokens = json_decode($csrfTokens[0], true);
$name = isset($csrfTokens[$this->prefix . '_name']) ? $csrfTokens[$this->prefix . '_name'] : false;
$value = isset($csrfTokens[$this->prefix . '_value']) ? $csrfTokens[$this->prefix . '_value'] : false;
}
if (!$name || !$value || !$this->validateToken($name, $value)) {
// Need to regenerate a new token, as the validateToken removed the current one.
$request = $this->generateNewToken($request);
$failureCallable = $this->getFailureCallable();
return $failureCallable($request, $response, $next);
}
}
// Generate new CSRF token if persistentTokenMode is false, or if a valid keyPair has not yet been stored
if (!$this->persistentTokenMode || !$this->loadLastKeyPair()) {
$request = $this->generateNewToken($request);
}
// Enforce the storage limit
$this->enforceStorageLimit();
return $next($request, $response);
}
}
well after several attempts over the last day and narrowing it down to the fetch api was using I decided to go back to the trusted jQuery aJax methods, and this seems to have worked.
Seems the following body and the new FormData() was not being picked up:
fetch('/post/url',{
method: 'POST',
body: new FormData(theForm)
So switched it out for
$.ajax({
url : '/url/to/post',
type: "POST",
data: {key:value, kay:value}
And all worked well.
The next issue to look into then is the keys being refreshed on first ajax call, preventing anymore calls unless page is refreshed, but thats for another day
I had another go at this after reading one of the blogs from one of the creators. So you can ignore my previous answer.
Sending the csrf in the body with these headers passes the csrf check.
const data = {
'csrf_name': csrf_name,
'csrf_value': csrf_value,
};
fetch(apiUrl, {
method: 'POST',
credentials: 'include',
body: JSON.stringify(data),
headers: {
'Content-Type': 'application/json, application/x-www-form-urlencoded; charset=utf-8',
},
}).then((response) => {
if (response.ok) {
return response.json();
}
return null;
}).then((json) => {
console.log(json);
}).catch(() => {
});
What finally helped me succeed with Slim PHP and the CSRF values while using fetch was adding credentials: 'include' to the fetch request, like:
const body = JSON.stringify({
csrf_name: csrfName.value,
csrf_value: csrfValue.value
// You can add more data here
});
fetch('/some/request', {
method: 'POST',
body: body,
credentials: 'include',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json'
},
}).then(...)

response for preflight is invalid (redirect) error

I am new to Laravel and Lumen framework. I am doing my first project using Lumen. I am trying to create an API calling from angular
Here is my angular code :
app.controller('ListCtrl', ['$scope', '$http', '$location', '$window', function($scope, $http, $location, $window) {
$scope.data = {};
$scope.getdata = function() {
$scope.datas = [];
$headers = {
'Access-Control-Allow-Origin' : '*',
'Access-Control-Allow-Methods' : 'POST, GET, OPTIONS, PUT',
'Content-Type': 'application/json',
'Accept': 'application/json'
};
$http({
url: "http://localhost/service/public/getdata/",
method: "GET",
params: {'place':$scope.data.place,'pincode':$scope.data.pincode},
headers: $headers
})
.success(function(data,status,headers,config) {
$scope.datas=JSON.stringify(data);
console.log($scope.datas);
$scope.navig('/show.html');
})
.error(function(){
alert("failed");
});
};
$scope.navig = function(url) {
$window.location.href = url;
};
}]);
And here is my Lumen route.php :
<?php
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Headers: Content-Type");
$app->get('/', function () use ($app) {
return $app->version();
});
$app->get('getdata','App\Http\Controllers\PlaceController#index');
And here is PlaceController.php
<?php
namespace App\Http\Controllers;
use App\Places;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
class PlaceController extends Controller
{
public function __construct()
{
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Headers: Content-Type");
//header("Access-Control-Allow-Origin: http://localhost:8100");
}
public function index()
{
$places = Place::all();
return response()->json($places);
}
}
But it shows "XMLHttpRequest cannot load http://localhost/service/public/getdata/?place=sdfs. Response for preflight is invalid (redirect)" error in console.log.
I have googled for two days,but cant find a solution.
Please help
You might be having problems due to invalid/incorrect Headers in your request. The only type of header that PlaceControllerseems to allow is Content-Type, but you're sending more than that.
Also, Access-Control-Allow-Origin and Access-Control-Allow-Methods headers should be added to the server response for your request, not to the request itself.
From MDN, cross-site requests (which seems to be your case) have to meet the following conditions:
The only allowed methods are:
GET
HEAD
POST
Apart from the headers set automatically by the user agent (e.g. Connection, User-Agent, etc.), the only headers which are allowed to be manually set are:
Accept
Accept-Language
Content-Language
Content-Type
The only allowed values for the Content-Type header are:
application/x-www-form-urlencoded
multipart/form-data
text/plain
Note: I never worked with Laravel or Lumen, but in my case if I don't set the headers correctly I end up with the same response for preflight is invalid (redirect) error.

Categories