PHP Rest API Endpoint Function Will Echo Stop Further Processing - php

class REST {
// this section is from http://www.tutorialsface.com/2016/02/simple-php-mysql-rest-api-sample-example-tutorial/
public function response($data,$status){
$this->_code = ($status)?$status:200;
$this->set_headers();
echo $data;
exit;
}
}
class API extends REST {
private function create_booking(){
if($this->get_request_method() != "POST"){
echo $this->response('Method Not Acceptable',406);
}
/*pseudocode for processing data if method is POST*/
Find whether record exists.
If exist {
set $message = "record found"
} else {
If not exist, insert record
set $message = "record inserted"
}
echo $this->response($message,200);
}
}
I would like to know, if let's say I have an API end point using the above method, when user is not using POST, will system stop processing after echo the error 406, or it will still continue after existing IF statement.
I have users submitting a new booking to this end point several times due to server did not response a message. End up I have duplicate bookings in my database.
What could lead to such incident?

Yes, it will execute further, but you need to stop further execution. You can add a simple return in your method below the echo message to quit the method:
if($this->get_request_method() != "POST"){
echo $this->response('Method Not Acceptable',406);
return;
}

Related

How to avoid PHP nested if...else... conditions and write clean, easy to understand code?

I am writing a login method in codeigniter where user will enter email and password and then it will do following things:
Validate user input -> If valid do point#2
Get user details from database -> If success query do point#3
Verify the password -> If verified login to the system
I know I can achieve the above by using pure nested if...else condition but then it will be very tedious and hard to read.
So, I tried it in this way -
// Empty array to hold processing errors
$processing_errors = array();
// Check for valid input
if(!$is_valid_input) array_push($processing_errors, "Invalid inputs");
// Get user details
if($get_user_details)
{
// Verify the user
if(!$is_correct_user) array_push($processing_errors, "Incorrect username or password.");
}
else array_push($processing_errors, "Database query error");
// Check if processing errors is empty
if(empty($processing_errors)) echo "Successfully logged in."; // Success
else foreach($processing_errors as $errors) echo $errors; // Errors
But the problem with above approach is it will still execute the code after Check for valid input even if it returns false and will take unnecessary processing time.
What is the best approach to write neat and clean readable code?
You can break these into methods exposing only the login request method and keeping everything else internal(as in private methods) as shown below. userLogin is where the request comes in.
Snippet:
class LoginController extends CI_Controller{
private $errors;
function __construct(){
$this->errors = []; // initialize error bag to an empty array
/*
load needed models
*/
}
private function validateInput($post_data){
/*
validate user details
*/
if(!$is_valid_input){
$this->errors[] = '';
}
return $is_valid_input;
}
private function getUserDetails($post_data){
/*
get the user data using models
*/
return $user_data;
}
private function verifyUser($post_data){
$user_data = $this->getUserDetails($post_data);
$is_correct_user = $user->email == $post_data['email'] && password_verify($post_data['password'],$user->password);
if(!$is_correct_user){
$this->errors[] = 'Incorrect username or password.';
}
return $is_correct_user;
}
private function displayErrors(){
foreach($this->errors as $current_error){
echo $current_error,"<br/>";
}
}
public function userLogin(){
$data = $this->input->post();
try{
if($this->validateInput($data) && $this->verifyUser($data)){
echo "Successfully logged in";
/* Your futher code */
}else{
$this->displayErrors();
}
}catch(Exception $e){
echo $e->getMessage(); // if you throw some Exception in your model for some situations. Better to have exact class name of Exception for faster lookup of the class
}
}
}

Why does if($signup->signup(...)) return with the message "Signup failed" while signup was successful?

So I've noticed something in php that I don't really understand
Say I have a simple signup function like this:
Class signup extends Connect{
function __construct(){
parent::__construct();
parent::connect();
}
function signup($username,$password){
$res=$this->conn->prepare("INSERT INTO users(username,password)
VALUES(?,?)");
$res->bindparam(1,$username);
$res->bindparam(2,$password);
$res->execute();
}
}
And in another file, I want to check whether the signup was successful like this:
require("signup.php");
$signup=new signup();
if($signup->signup(...)){
echo "Signed up";
}
else{
echo "Signup failed";
}
And this statement will return with Sigup failed if I have succesfully signed up, and will get Signed up if it failed.
I assumed that this means if the function signup ran successfully, that means the sign up was successful so the message should be Signed up
But if I do use ! in the if statement like this:
if(!$signup->signup(...)){
echo "Signed up";
}
else{
echo "Signup failed";
}
In this case Signed up will be echoed if the data were correct and the signup was successful as it should be.
Don't misunderstand my question,the code works properly, there's no error, I'm just curious why it works this way.
Thanks for any answers!
PS:The codes above are not complete code
The signup() method has no return statement, so it returns null by default, which is falsey. You need to return an indication of whether the query was successful.
function signup($username,$password){
$res=$this->conn->prepare("INSERT INTO users(username,password) VALUES(?,?)");
$res->bindparam(1,$username);
$res->bindparam(2,$password);
return $res->execute();
}

Strange behavior with flashdata in codeigniter

I have found very strange behavior of "if" condition and session flashdata in codeigniter,
public function edit_equip($equip_id, $company_id) {
$this->data['section_title'] = 'Edit Equipment';
$this->data['equip_detail'] = $equip_detail = $this->common->select_data_by_id('equipment', 'id', $equip_id, '*', array());
if (empty($equip_detail)) {
$this->session->set_flashdata('error', 'Error Ouccrred. Try Again!');
redirect('Company/equipment/' . $company_id, 'refresh');
}
//some other code
$this->load->view('company/edit_equip', $this->data);
}
this is a function of my Equipment class. Now when I call below url like,
http://localhost/scale/Equipment/edit_equip/1/2
then edit view will open correctly. but now when I press F5 button or browser refresh button then it is showing "Error Ouccrred. Try Again!" flash message which I have set in above if condition. I am not understand why this is happening, because $equip_detail contains data and I have also try to die in it but it is not going into if which is correct so why only $this->session->set_flashdata('error', 'Error Ouccrred. Try Again!');
is providing effect?
in conclusion my code is not running if block but if i press F5 or browser refresh button after first time my view is loaded it is showing me error message which is set in if condition, but my code is not going to it otherwise it has to redirect but it is loading view page with flash message.
I have only set this flash message at only one place as per above code. I am using codeigniter 3.1.6
Please can anyone explain me this?
This isn't the solution, but more of an investigation to satisfy yourself how things are working...
So when things go "screwy", its always a good time to go back to basics. So seeing as you are so convinced your code is executing correctly but giving you unexpected results here is some test code just to check out the behavior of flashdata.
Flash_session_test.php
class Flash_session_test extends CI_Controller
{
public function __construct()
{
parent::__construct();
$this->load->library('session');
$this->load->helper('url');
}
public function index()
{
echo "This is " . __METHOD__;
$this->test_display();
}
/**
* Mockup code derived from sample code
* to test the behavior of the flash data.
*
* #param $equip_id
*/
public function edit_equip($equip_id)
{
echo "This is " . __METHOD__;
// Set up our Fail / Pass for the If statement below.
if (isset($equip_id)) {
if ($equip_id == 'fail') {
// Create a Fail Condition
$equip_detail = null;
} else {
// Create a Pass Condition
$equip_detail = array('fred' => 1);
}
}
// The code we are testing.
if (empty($equip_detail)) {
$this->session->set_flashdata('error', 'Error Occurred. Try Again!');
// Redirect and display the flashdata error message
redirect('/flash_session_test', 'refresh');
}
$this->test_display();
}
/**
* Our Test "View" put here for simplicity
*/
public function test_display()
{
echo '<br>';
echo '<a href="/flash_session_test/edit_equip/pass" >Click here to Create a PASS</a>';
echo '<br>';
echo '<a href="/flash_session_test/edit_equip/fail" >Click here to Create an ERROR</a>';
echo '<br>';
echo '<br>';
// Only display the message if we have one
$error = $this->session->flashdata('error');
if ($error === null) { // If null, then It doesn't exist
echo '<div style="color:green">';
echo "Not An Error in Sight!";
echo '</div>';
} else {
echo '<div style="color:red">';
echo $this->session->flashdata('error');
echo '</div>';
echo "Now Refresh the page!";
}
}
}
Note: This will run standalone, without relying on your existing code.
the CI manual says:
CodeIgniter supports “flashdata”, or session data that will only be
available for the next request, and is then automatically cleared.
F5 is sending a new request, so flashdata is cleared
Don't use $this->session->set_flashdata(), use $this->session->mark_as_flash() instead, it worked for me!

Codeigniter form validation: run function is not working

I am working with a from in codeigniter where program control is moving to submit function which I can test by adding the die function. Although set_rules() are successfully checking the entry but the control is not being passed to if($this->form_validation->run()) this function. Its getting out of it and running the die function dead-2 that I have kept to test the program flow.
Below is my controller code
function addPost(){
$this->load->library('form_validation')
if($this->admin_lib->checkMembers()){
if($this->input->post('submit')){
//validate the form
$this->form_validation->set_rules('country','Country','required');
$this->form_validation->set_rules('city','City','required');
$this->form_validation->set_rules('area','Area','required');
$this->form_validation->set_rules('street','Street','required');
$this->form_validation->set_rules('house_no','House number','required|numeric');
if($this->form_validation->run()){
//add to database
die("dead-1");
if($this->members_model->addPost())
{
echo "Successfully made one entry will be validated";
}
else{
echo "Error uploading the datas into database Please contact us about the problem";
}
}
die("Dead -2");
}
$data['content']=$this->load->view('members/addPost','',true);
$this->load->view('members/home',$data);
}
else{
echo "you dont have preveledge to access this page ,<br/> LOgin link rakhnu paryo ";
}
}
Your code will always call die("Dead -2") because it isn't part of an Else block. It's sitting directly below your If statement which means, regardless of what happens with your form validation, it will always die.
Consider changing your code to the following
if($this->form_validation->run())
{
//add to database
die("dead-1");
if($this->members_model->addPost())
{
echo "Successfully made one entry will be validated";
}
else
{
echo "Error uploading the datas into database Please contact us about the problem";
}
}
else
{
die("Dead -2");
}

Refactoring loop with conditionals

given a loop that sends an email to all subscriptions in an array
foreach($subscriptions as $s){
if(!$s->send_email()){
}
}
What would be the cleanest way to trigger a callback if all models have mailed successfully or show an error if one of the models fails to mail. Is it common to save all error messages till the end of the loop and print them as a whole, or break the loop with an error.
I'm using this in combination with a JSON REST API saving a project (/projects/1) which in turn emails all users.
The method I'm using now feels dirty with lot's of nested if else, sending 3 different response on different places
if($project->save()){
$subscriptions = Subscription::model()->findAllByAttributes(array('planning_id' => $planning->id));
foreach($subscriptions as $s){
if(!$s->send_email()){
$errors[] = "failed to send email. Subscription ". $s->id;
}
}
if(count($errors) > 0){
//send json api response with error response
} else {
//send json api success response
}
} else {
//send json api response with project error response
}
I was wondering what convention is concerning this
It is a little messy - and it combines multiple concerns within the "save" function - anyone reading the code needs to understand what "save" means, how we loop through the contacts etc.
I'd refactor it as follows:
if($project->save()){
$subscriptions = Subscription::model()->findAllByAttributes(array('planning_id' => $planning->id));
$errors = sendMailToSubscribers($subscriptions);
$response = determineResponse($errors);
// send JSON API response
} else {
//send json api response with project error response
}
function sendMailToSubscribers($subscriptions){
foreach($subscriptions as $s){
if(!$s->send_email()){
$errors[] = "failed to send email. Subscription ". $s->id;
}
}
return $errors;
}
function determineResponse($errors){
if(count($errors) > 0){
//return json api response with error response
} else {
//return json api success response
}
}
You can use while logic so that failure falls through to the end of the block.
while(1) {
if ($project->save()) {
foreach($subscripts as $s)
if (!$s->send_email())
$errors[] = "failed to send email. Subscription ". $s->id;
} else
$errors[] = 'failed to save the project';
if (empty($errors)) {
//send success here
break;
}
//send your errors here
break;
}

Categories