I have a issue with my slim app, i want send json responses but with customed headers. My code is like follow:
index.php
require 'vendor/autoload.php';
require 'app/config.php';
require 'app/libs/api.cs.php';
$app = new Slim\App(
[
"settings" => $config,
"apics" => function() { return new APIHelper(); } //This is a class that contain a "helper" for api responses
]
);
require 'app/dependences.php';
require 'app/middleware.php';
require 'app/loader.php';
require 'app/routes.php';
// Run app
$app->run();
app/libs/api.cs.php (The "helper")
<?php
class APIHelper
{
public function sendResponse($response, $status='success' ,$code = 200, $message = "", $data = null)
{
$arrResponse = array();
$arrResponse['status'] = $status;
$arrResponse['code'] = $code;
$arrResponse['message'] = $message;
$arrResponse['data'] = $data;
return $response
->withHeader('Access-Control-Allow-Origin', '*')
->withHeader('Access-Control-Allow-Headers', 'X-Requested-With, Content-Type, Accept, Origin, Authorization, AeroTkn')
->withHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS')
->withHeader('Content-Type','application/json')
->withHeader('X-Powered-By','My API Server')
->withJson($arrResponse,$code);
}
}
my routes file (app/routes.php)
$app->group('/foo', function () {
$this->get('', function ($req, $res, $args) {
return $this->apics->sendResponse($res, 'success' ,200, "Foo API Index By Get", null);
});
$this->post('', function ($req, $res, $args) {
try{
$oBody = $req->getParsedBody();
return $this->apics->sendResponse($res, 'success' ,200, "Foo API POST Response", $oBody);
}
catch(\Exception $ex){
return $this->apics->sendResponse($res, 'error' ,500, "Process Error", array('error' => $ex->getMessage()));
}
});
});
When i trying to run my app with request body, the result is the follow:
Headers:
connection →Keep-Alive
content-type →text/html
date →Wed, 30 Aug 2017 02:22:56 GMT
keep-alive →timeout=2, max=500
server →Apache
transfer-encoding →chunked
Body (returns as simple text and not json encoded)
{"status":"success","code":200,"message":"Foo API POST Response","data":{"one":"1", "two":"2"}}
I've trying put this class as a middleware, but i'm some confused in these subject.
Can you help me telling me if these method is good or where i'm bad.
Thanks to all and i hope for your answers! Nice day
Using Middleware is the ideal answer for your problem
Just add this function in your middeleware file
$app->add(function ($req, $res, $next) {
$response = $next($req, $res);
return $response
->withHeader('Access-Control-Allow-Origin', 'http://mysite')
->withHeader('Access-Control-Allow-Headers', 'X-Requested-With, Content-Type, Accept, Origin, Authorization')
->withHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
->withHeader('Content-Type','application/json');
->withHeader('X-Powered-By','My API Server');
});
I found the "error" was a kindergarden issue hahaha, I've download all my code from the web server for test in my machine, I have the same result, but i found that all my files had strange characters at start, so i re-save the files as utf-8 and the problem is solved. Little details that can create headaches!. Thanks to Nica and Ramy. Ramy: the solution was excellent, now the code are more organizated, i take this practice. Good day to all.
Related
My angular application runs on http://localhost:4200/ and my Slim4 application runs on localhost:8080. When I try to integrate APIS between angular and slim, GET API works fine, but the POST API does not. I get the below CORS error,
Access to XMLHttpRequest at 'http://localhost:8080/admin/login' from origin 'http://localhost:4200' has been blocked by CORS policy: Request header field cache-control is not allowed by Access-Control-Allow-Headers in preflight response.
My angular request 'content-type' is 'applictaion/json'. Please find the slim4 response header below,
<?php
declare(strict_types=1);
namespace App\Application\ResponseEmitter;
use Psr\Http\Message\ResponseInterface;
use Slim\ResponseEmitter as SlimResponseEmitter;
class ResponseEmitter extends SlimResponseEmitter
{
/**
* {#inheritdoc}
*/
public function emit(ResponseInterface $response): void
{
// This variable should be set to the allowed host from which your API can be accessed with
$origin = isset($_SERVER['HTTP_ORIGIN']) ? $_SERVER['HTTP_ORIGIN'] : '';
$response = $response
->withHeader('Access-Control-Allow-Credentials', 'true')
->withHeader('Access-Control-Allow-Origin', $origin)
->withHeader(
'Access-Control-Allow-Headers',
'X-Requested-With, Content-Type, Accept, Origin, Authorization',
)
->withHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, PATCH, DELETE, OPTIONS')
->withHeader('Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0')
->withAddedHeader('Cache-Control', 'post-check=0, pre-check=0')
->withHeader('Pragma', 'no-cache');
if (ob_get_contents()) {
ob_clean();
}
parent::emit($response);
}
}
Have you tried this?
->withHeader('Access-Control-Allow-Origin', '*')
I've tried to set up a Angular App with SLIM Framework v4 Backend; Angular is running local, while Slim is on a Deploy Server. So CORS Setup is needed and I did like given in the documentation:
$app->options('/{routes:.+}', function ($request, $response, $args) {
return $response;
});
$app->add(function ($request, $handler) {
$response = $handler->handle($request);
return $response
->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, PATCH, OPTIONS');
});
On get Requests the Acces-Control-Allow-Origin Header is present; no problem, everything working as expected. On Put request (example):
$app->put('/event/{id}', function (Request $request, Response $response, $args) use ($app) {
$id = $args['id'];
$response
->withHeader('Access-Control-Allow-Origin', '*')
->withHeader('Access-Control-Allow-Headers', 'X-Requested-With, Content-Type, Accept, Origin, Authorization');
$response->getBody()->write('Test with $id');
return $response;
});
even with an additional add in the function, the header is not present on the response in the browser.
What am I doing wrong?
The request and response object is immutable. You can try this:
$app->put('/event/{id}', function (Request $request, Response $response, $args) {
$id = $args['id'];
$response = $response
->withHeader('Access-Control-Allow-Origin', '*')
->withHeader('Access-Control-Allow-Headers', 'X-Requested-With, Content-Type, Accept, Origin, Authorization');
$response->getBody()->write('Test with $id');
return $response;
}
I would like to make a get request from my Ionic app to an API build with the Slim Framework.
This is the code of the API:
<?php
header('Access-Control-Allow-Origin: *');
header('Content-Type: application/json');
?>
<?php
use \Psr\Http\Message\ServerRequestInterface as Request;
use \Psr\Http\Message\ResponseInterface as Response;
use Tuupola\Middleware\HttpBasicAuthentication;
require 'vendor/autoload.php';
$jwt_secret = '**************';
$app = new Slim\App;
$app->add(new Tuupola\Middleware\JwtAuthentication([
"path" => "/api",
"attribute" => "jwt",
"secret" => $jwt_secret, "error" => function ($response, $arguments) {
$data["status"] = "error";
$data["message"] = $arguments["message"];
return $response
->withHeader("Content-Type", "application/json")
->withHeader("Access-Control-Allow-Origin", "*")
->getBody()->write(json_encode($data, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT));
}
]));
$app->get('/api/hello', function (Request $request, Response $response, array $args)
{
$decoded = $request->getAttribute("jwt");
$response->getBody()->write(json_encode(array("status"=> "200", "message" => "HELLO ".$decoded['uid'] ." - " . $decoded['cus'])));
return $response;
});
$app->get('/', function (Request $request, Response $response, array $args) {
$response->getBody()->write(json_encode(array("status"=> "200", "message" => "Welcome to the API")));
return $response;
});
$app->run();
?>
When I'm testing with postman the API works fine. But when I'm trying to call it with the HTTPClient in Ionic, it doesn't work. This is my Ionic Code:
import { Component } from '#angular/core';
import { HttpClient, HttpHeaders } from '#angular/common/http';
#Component({
selector: 'app-home',
templateUrl: 'home.page.html',
styleUrls: ['home.page.scss'],
})
export class HomePage {
constructor(private http: HttpClient)
{
}
sendRequest()
{
this.http.get('http://localhost/slim3',).subscribe((data)=>console.log(data));
}
}
The Error message is the following:
:8100/home:1 Access to XMLHttpRequest at 'http://localhost/slim3' from origin 'http://localhost:8100' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
core.js:6014 ERROR HttpErrorResponse {headers: HttpHeaders, status: 0, statusText: "Unknown Error", url: "http://localhost/slim3", ok: false, …}
How can I fix it? Thanks!
You must enable CORS(What is CORS?) in Slim Framework. Check http://www.slimframework.com/docs/v3/cookbook/enable-cors.html
Add this before $app->run(); (replacing http://mysite by your url, including port)
$app->options('/{routes:.+}', function ($request, $response, $args) {
return $response;
});
$app->add(function ($req, $res, $next) {
$response = $next($req, $res);
return $response
->withHeader('Access-Control-Allow-Origin', 'http://mysite')
->withHeader('Access-Control-Allow-Headers', 'X-Requested-With, Content-Type, Accept, Origin, Authorization')
->withHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, PATCH, OPTIONS');
});
I am trying to post user data to a PHP RESTful API from my ionic app. I tried searching for a solution but was of no help. I have created a provider containing a function namely "onSignup(signupForm)" which is being called on button click.
The code is as follows:
signup(username: string,email: string,password: string): void {
let headers = new HttpHeaders();
headers = headers.set("Content-Type","application/json; charset=UTF-8");
let body= {
name:username, email:email, password:password
};
this.http.post('http://www.something.com/register', JSON.stringify(body),
{headers: headers})
.subscribe(data => {
console.log(data);
});
this.storage.set(this.HAS_LOGGED_IN, true);
this.setUsername(username);
this.events.publish('user:signup');
};
The code for the api is as:
<?php
header("Access-Control-Allow-Origin:*");
header("Content-Type: application/json; charset=UTF-8");
require_once '../include/DbHandler.php';
require_once '../include/PassHash.php';
require '.././libs/Slim/Slim.php';
\Slim\Slim::registerAutoloader();
$app = new \Slim\Slim();
/**
* ----------- METHODS WITHOUT AUTHENTICATION -------------------------------
--
*/
/**
* User Registration
* url - /register
* method - POST
* params - name, email, password
*/
$app->post('/register', function() use ($app) {
file_put_contents("logs.txt","/register Route has been visited");
// check for required params
verifyRequiredParams(array('name', 'email', 'password'));
$response = array();
// reading post params
$name = $app->request->post('name');
$email = $app->request->post('email');
$password = $app->request->post('password');
// validating email address
validateEmail($email);
$db = new DbHandler();
$res = $db->createUser($name, $email, $password);
if ($res == USER_CREATED_SUCCESSFULLY) {
$response["error"] = false;
$response["message"] = "You are successfully registered";
} else if ($res == USER_CREATE_FAILED) {
$response["error"] = true;
$response["message"] = "Oops! An error occurred while registereing";
} else if ($res == USER_ALREADY_EXISTED) {
$response["error"] = true;
$response["message"] = "Sorry, this email already existed";
}
// echo json response
echoRespnse(201, $response);
});
The error I receive is
Failed to load resource: the server responded with a status of 404 (Not Found).
Failed to load http://www.something.com/register: Response for preflight has invalid HTTP status code 404
This API is working perfectly in Postman, but is facing the issue when I am running the app in Chrome.
Is there something I am missing in the API or during the POST call?
Please help. Thanks in Advance.
Edit:
I have added the Network Tab screenshot. This is what I am getting in my Request and Response Headers. I guess there might be a mismatch in the two headers and definitely it can't be a CORS issue because I can make GET calls without any CORS issue.
Added the console tab screenshot with the errors:
Since it is working from Postman but not your application I would take a good look into CORS. You need to set your headers when a request comes in, for post requests the Angular HttpClient will send an OPTIONS request.
I don't use PHP much, but maybe something like this would work
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: POST, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type');
header('Content-Length: 0');
header('Content-Type: application/json');
die();
}
Edit: Since you are using the Slim Framework I assume by your provided code. You can address OPTIONS requests like so as described per the Slim Framework v2 Docs (Not sure what version you are using).
$app->options('/register', function ($app) {
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: POST, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type');
header('Content-Length: 0');
header('Content-Type: application/json');
die();
});
Or you could maybe set the headers like so, as described by
https://www.slimframework.com/docs/v2/response/headers.html
$app->response->headers->set('Access-Control-Allow-Origin', '*');
$app->response->headers->set('Access-Control-Allow-Methods', 'POST, OPTIONS');
$app->response->headers->set('Access-Control-Allow-Headers', 'Content-Type');
$app->response->headers->set('Content-Type', 'application/json');
try this
header('Access-Control-Allow-Origin: *');
$dados = file_get_contents('php://input');
you will get a JSON from your angular request...
I have the same problem again.
Old post here
I have a angular app and SlimFramework for api connect.
Local it works fine but when i publish to my Website come the error that my Header no set.
But the info on the API testing tool says it's allowed from * IP.
Can someone help me?
Here a valid token: Basic TyOSZcfBwMC6DR9kbAWeMnPmhF4ohZu2n9LccQEyt6uXNt8PTT
Thx
$app = new \Slim\App(["settings" => $config]);
$container = $app->getContainer();
$app->options('/{routes:.+}', function ($request, $response, $args) {
return $response;
});
$app->add(function ($req, $res, $next) {
$response = $next($req, $res);
return $response
->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, OPTIONS, DELETE, PUT');
});
$container['logger'] = function($c) {
$logger = new \Monolog\Logger('my_logger');
$file_handler = new \Monolog\Handler\StreamHandler("../../logs/app.log");
$logger->pushHandler($file_handler);
return $logger;
};
$app->get('/token', function ($request, $response){
$db = new DbOperation();
if (!$request->hasHeader('Authorization')) {
return $response->withJson([
"success"=> false,
"message" => "Header not set.",
"textcode"=> "MSG2"
], 401);
}
$token = $request->getHeader('Authorization');
if($db->checkToken($token[0])){
$user = $db->userInfo($token[0]);
if($db->checkActivate($user['auth_user'])){
if($db->checkExpired($user['auth_user'])){
return $response->withJson([
"success"=> false,
"message" => "The validity of the login has expired. If you have any questions, please contact the administrator..",
"textcode"=> "MSG6"
], 401);
} else {
return $response->withJson(["success"=> true], 200);
}
} else {
return $response->withJson([
"success"=> false,
"message" => "This account has not yet been activated.",
"textcode"=> "MSG8"
], 401);
}
} else {
return $response->withJson([
"success"=> false,
"message"=>'Invalid token',
"textcode"=> "MSG1"
], 403);
}
});
Your basic auth credentials do not decode into anything meaningful. PHP tends to silently ignore Authorization headers which it thinks are malformed. Try with something like Basic dGVzdDp0ZXN0 which decodes into test:test.
Workaround for this has however been added to Slim starting from version 3.5.0. Upgrading your Slim installation might also help.