I have been using Slim v2 for my APIs and am thinking about upgrading to v3.
Unfortunately I have limited experience and could use your help on a code example below.
This is the login code:
$app->post('/register', function() use ($app) {
// 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);
});
Here is the validateEmail function:
function validateEmail($email) {
$app = \Slim\Slim::getInstance();
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
$response["error"] = true;
$response["message"] = 'Email address is not valid';
echoRespnse(400, $response);
$app->stop();
}
}
How do I get an Instance of app in Slim v3 to actually stop the app when input criteria are not met?
I would appreciate it if you could give me an example with the help of my code.
Thanks for the help!
EDIT
The above issue was solved. Unfortunately, a new issue arose after checking my code.
I have a middle layer to authenticate the user:
function authenticate(\Slim\Route $route) {
// Getting request headers
$headers = apache_request_headers();
$response = array();
$app = \Slim\Slim::getInstance();
// Verifying Authorization Header
if (isset($headers['Authorization'])) {
//omitted code
} else {
// api key is missing in header
$response["error"] = true;
$response["message"] = "Api key is misssing";
echoRespnse(400, $response);
$app->stop();
}
In my main code i implement function authenticate as follows:
$app->get('/tasks', 'authenticate', function() {
global $user_id;
$response = array();
$db = new DbHandler();
//ommit some code
echoRespnse(200, $response);
});
Would you know how to do this in Slim v3?
I would really appreciate your help.
In Slim3, return $response (return Response object) is a better way to stop app.
So how is the below?
$app->post('/register', function($request, $response, $args) {
// omit some codes
if(!validateEmail($request->getParsedBodyParam('email'))){
return $response->withJson(['message' => 'Email address is not valid', 'error' => true], 400);
}
// omit some codes
}
validateEmail function is changed to like below.
function validateEmail($email) {
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
return false
}
return true;
}
Hope it will help you.
Related
In Authorize.Net created the subscription and recurring events handling using webhook. When I test using the web hook account authentication works but in actual webhook notification always failed authentication
if (isset($this->header['x-anet-signature'])) {
$json = Json::encode($this->body);
if ($json) {
//To check the header and signature is true
if (hash_equals(strtolower($this->header['x-anet-signature']),
'sha512=' . hash_hmac('sha512',$json, $secret))
) {
}else{
yii::info($json,'webhookhNotifications');
throw new \yii\web\ServerErrorHttpException('Authentication failed in Webhook');
return false;
}
}
}
Webhook JSON
{
"notificationId":"4bbba8fb-1d32-46b6-a513-a9ca2fed885c",
"eventType":"net.authorize.customer.subscription.created",
"eventDate":"2019-11-27T06:20:36.3621687Z",
"webhookId":"a2929d59-147e-4400-a2bb-b3bd25a0311d",
"payload":{
"name":"Test subscription",
"amount":290.00,
"status":"active",
"profile":{
"customerProfileId":1921894828,
"customerPaymentProfileId":1834842681,
"customerShippingAddressId":1879009509
},
"entityName":"subscription",
"id":"6168233"
}
}
Secret key
F7B582AFFA9372866965456CFAC0D1B1219258F955FD5266D1A96BF9BE3C85F7D54C7CDFF9EF3EE7D3916EACB5EE920167F557BBB307288C17FBD169F0257AB4
x-anet-signature
sha512=FDE5518801C115C4886311877B4C37F6C26ABACE01ADB973EF372FB51C8F1E5321A83717161AD7DEFFD46F5013900E68B6220F3B25E9302A4208A9C673D32749
Your code should work. I simplified it a bit for testing purposes but using the values you provided above it does indeed validate successfully:
$signature = 'sha512=FDE5518801C115C4886311877B4C37F6C26ABACE01ADB973EF372FB51C8F1E5321A83717161AD7DEFFD46F5013900E68B6220F3B25E9302A4208A9C673D32749';
$json = '{"notificationId":"4bbba8fb-1d32-46b6-a513-a9ca2fed885c","eventType":"net.authorize.customer.subscription.created","eventDate":"2019-11-27T06:20:36.3621687Z","webhookId":"a2929d59-147e-4400-a2bb-b3bd25a0311d","payload":{"name":"Test subscription","amount":290.00,"status":"active","profile":{"customerProfileId":1921894828,"customerPaymentProfileId":1834842681,"customerShippingAddressId":1879009509},"entityName":"subscription","id":"6168233"}}';
$secret = 'F7B582AFFA9372866965456CFAC0D1B1219258F955FD5266D1A96BF9BE3C85F7D54C7CDFF9EF3EE7D3916EACB5EE920167F557BBB307288C17FBD169F0257AB4';
if (hash_equals(strtolower($signature), 'sha512=' . hash_hmac('sha512', $json, $secret))) {
echo 'valid';
}else{
echo 'invalid';
}
Demo
I think your error is you are encoding the JSON which is already JSON. So change this line:
$json = Json::encode($this->body);
new code:
if (isset($this->header['x-anet-signature'])) {
$json = $this->body;
if ($json) {
//To check the header and signature is true
if (hash_equals(strtolower($this->header['x-anet-signature']),
'sha512=' . hash_hmac('sha512',$json, $secret))
) {
}else{
yii::info($json,'webhookhNotifications');
throw new \yii\web\ServerErrorHttpException('Authentication failed in Webhook');
return false;
}
}
}
I have been following this tutorial Tutorial and i managed to create the rest api with slim.
here is my .htaccess
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ %{ENV:BASE}index.php [QSA,L]
just as in the example and then when i go to my index.php
http://localhost/thefaith/v1/user/register
i get a an error
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.
but all my files are well arranged
plus below is my index.php which is in the v1 folder
<?php
include_once '../Includes/account_db_handler.php';
require '.././libs/Slim/Slim.php';
\Slim\Slim::registerAutoloader();
$app = new \Slim\Slim();
// User register
$app->post('/user/register', function() use ($app) {
// check for required params
//verifyRequiredParams(array('name', 'email'));
$response = array();
// reading post params
//$name = $app->request->post('name');
//$email = $app->request->post('email');
// validating email address
//validateEmail($email);
//$db = new AcoountDbHandler();
//$response = $db->createUser($name, $email);
$response["message"] = "You are successfully registered";
// echo json response
echoRespnse(201, $response);
});
/**
* Verifying required params posted or not
*/
function verifyRequiredParams($required_fields) {
$error = false;
$error_fields = "";
$request_params = array();
$request_params = $_REQUEST;
// Handling PUT request params
if ($_SERVER['REQUEST_METHOD'] == 'PUT') {
$app = \Slim\Slim::getInstance();
parse_str($app->request()->getBody(), $request_params);
}
foreach ($required_fields as $field) {
if (!isset($request_params[$field]) || strlen(trim($request_params[$field])) <= 0) {
$error = true;
$error_fields .= $field . ', ';
}
}
if ($error) {
// Required field(s) are missing or empty
// echo error json and stop the app
$response = array();
$app = \Slim\Slim::getInstance();
$response["error"] = true;
$response["message"] = 'Required field(s) ' . substr($error_fields, 0, -2) . ' is missing or empty';
echoRespnse(400, $response);
$app->stop();
}
}
function echoRespnse($status_code, $response) {
$app = \Slim\Slim::getInstance();
// Http response code
$app->status($status_code);
// setting response content type to json
$app->contentType('application/json');
echo json_encode($response);
}
/**
* Validating email address
*/
function validateEmail($email) {
$app = \Slim\Slim::getInstance();
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
$response["error"] = true;
$response["message"] = 'Email address is not valid';
echoRespnse(400, $response);
$app->stop();
}
}
$app->run();
?>
am still new using slim, need some help on how to solve this
This question already has answers here:
Call to undefined function apache_request_headers()
(6 answers)
Closed 5 years ago.
I'm only posting this because none of the other posts have helped solve my problem. I'm using slim and advanced rest api app on chrome for testing. I've tried many suggestions on the web but nothing is working. I'm running php 5.5 on hostgator. I am getting the error when passing authorization header:
call to undefined function apache_request_headers()
<?php
require_once '../include/DbHandler.php';
require_once '../include/PassHash.php';
require '.././libs/Slim/Slim.php';
\Slim\Slim::registerAutoloader();
$app = new \Slim\Slim();
// User id from db - Global Variable
$user_id = NULL;
function authenticate(\Slim\Route $route) {
// Getting request headers
$headers = apache_request_headers();
$response = array();
$app = \Slim\Slim::getInstance();
// Verifying Authorization Header
if (isset($headers['Authorization'])) {
$db = new DbHandler();
// get the api key
$api_key = $headers['Authorization'];
// validating api key
if (!$db->isValidApiKey($api_key)) {
// api key is not present in users table
$response["error"] = true;
$response["message"] = "Access Denied. Invalid Api key";
echoRespnse(401, $response);
$app->stop();
} else {
global $user_id;
// get user primary key id
$user_id = $db->getUserId($api_key);
}
} else {
// api key is missing in header
$response["error"] = true;
$response["message"] = "Api key is misssing";
echoRespnse(400, $response);
//echoRespnse(400, $headers);
$app->stop();
}
}
.htaccess
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ %{ENV:BASE}index.php [QSA,L]
SetEnvIf Authorization "(.*)" HTTP_AUTHORIZATION=$1
Updating, this seems to take care of the the header problem
if (!function_exists('apache_request_headers')) {
function apache_request_headers() {
foreach($_SERVER as $key=>$value) {
if (substr($key,0,5)=="HTTP_") {
$key=str_replace(" ","-",ucwords(strtolower(str_replace("_"," ",substr($key,5)))));
$out[$key]=$value;
}else{
$out[$key]=$value;
}
}
return $out;
}
}
PHP 5.4.0 and later supports apache_request_headers(). But there are other solutions like the code below which comes from: http://php.net/manual/en/function.apache-request-headers.php
function apache_request_headers() {
$arh = array();
$rx_http = '/\AHTTP_/';
foreach($_SERVER as $key => $val) {
if( preg_match($rx_http, $key) ) {
$arh_key = preg_replace($rx_http, '', $key);
$rx_matches = array();
// do some nasty string manipulations to restore the original letter case
// this should work in most cases
$rx_matches = explode('_', $arh_key);
if( count($rx_matches) > 0 and strlen($arh_key) > 2 ) {
foreach($rx_matches as $ak_key => $ak_val) $rx_matches[$ak_key] = ucfirst($ak_val);
$arh_key = implode('-', $rx_matches);
}
$arh[$arh_key] = $val;
}
}
return( $arh );
}
I've got a problem with the file transfer plugin that i can't seem to figure out. My code works when i'm using http, but when I try to upload over https it seems that it doesn't send the parameters to my api but it does reach my api. only the the file is missing, the x-session-token header is present and valid. This is the code i use for uploading the file:
$scope.options = {};
$scope.options.fileKey = "file";
$scope.options.fileName = $scope.img.substr($scope.img.lastIndexOf('/') + 1);
$scope.options.mimeType = "image/jpeg";
$scope.options.headers = {
'x-session-token' : window.localStorage.auth
};
// parameters: source, filePath, options
$cordovaFile.uploadFile("https:/****/api.php/profielpic/", $scope.img, $scope.options, true).then(function(result) {
console.log(result);
$cordovaToast.showShortTop('Uploaden gelukt!').then(function(success) {
$ionicLoading.hide();
$state.go('tab.profiel');
}, function (error) {
$ionicLoading.hide();
$state.go('tab.profiel');
});
}, function(err) {
console.log(err);
$ionicLoading.hide();
});
This is the code i use Server side to see if there's anything:
$app->post('/profielpic/', function () use ($app) {
$auth = new api\src\Auth;
$users = new api\src\Users;
$authdata = json_decode($app->request->headers->get('x-session-token'));
$data = json_decode($app->request->getBody());
$userid = $authdata->userID ;
$session_token = $authdata->session_token;
$userdata = $data->userdata;
$alertsarray = array();
$message = null;
$isValid = true;
$authresult = $auth->authenticate($userid, $session_token);
$imgname = time();
print_r(json_encode($authdata));
print_r(json_encode($_FILES));
print_r(json_encode($_POST));
print_r(json_encode($data));
print_r(json_encode(file_get_contents("php://input")));
/*
if($authresult === true) {
$res = $users->updateUserPicture($userid, $_FILES['file']);
if($res === false) {
$isValid = false;
$message = "Er ging iets mis.";
}else{
$message = $res;
}
}else {
$isValid = true;
$message = $authresult;
}*/
$dataArray = array(
'isValid' => $isValid,
'message' => $message
);
echo ")]}',\n".json_encode($dataArray);
});
but everything is empty with https:// if i upload to http:// it works
Does anyone know why http works but https isn't working? the only case where https isn't working is with file uploads. the rest of my api routes work with https.
It happens on iOS devices and Android devices so the problem is more likely to be with the slim api i'd guess
Api response:
{
"bytesSent": 32889,
"responseCode": 200,
"response": "{\"userID\":\"2\",\"session_token\":\"****"
} {\
"file\":{\"name\":\"modified.jpg?1427448587960\",\"type\":\"image\\/jpeg\",\"tmp_name\":\"\\/tmp\\/phpABKyF2\",\"error\":0,\"size\":37491}}[]null\"\")]}',\n{\"isValid\":true,\"message\":null}",
"objectId": ""
}
Make sure you are using a valid SSL certificate. If your app is reaching the API but not sending the data, its likely that your app has realised the connection is unsafe. It will only send data once it establishes a secure connection to a server it can trust.
A self signed certificate will not be trusted.
// Process the forms
if (($this->getRequest()->isPost())
&& ($this->getRequest()->isXmlHttpRequest())) {
// Initiate response
$status = false;
$msg = '';
$zf = null;
// Error test
$form->getElement('no')->addError('This is the error message');
if ($form->isValid($this->getRequest()->getPost())) {
// Everything is good
$status = true;
} else {
// Get the error messages
$zf = $form->getMessages();
}
// Setup the response
$result = json_encode(array('status' => $status,
'msg' => $msg,
'zf' => $zf));
$this->_helper->viewRenderer->setNoRender();
$this->_helper->layout()->disableLayout();
$this->getResponse()->setHeader('Content-Type', 'application/json');
$this->getResponse()->setBody($result);
return;
} else {
// Populate the form
}
As you can see, I've used $form->getElement('no')->addError('This is the error message'); to force error on the form element, but $form->getMessages(); would still return NULL. So, what should I do to force error on the selected form element?
I think you've got the get the ErrorMessages()
$form->getErrorMessages()
I've opened a bug report for this issue: http://framework.zend.com/issues/browse/ZF-11088. I'll update this question if there's any new progress.