Using PHP and jQuery Ajax to build a basic log in system.
What I want to do is submit sections of a form via ajax and return an array. I'm not quite sure if I've got this one right.
Here is the PHP
if($access_function == 'access_login_1'){
$email = $_POST['access_email'];
$pwd = $_POST['access_pwd'];
if(!$email || !$pwd){
$error = 'Empty';
}
else {
$user = get_user($email);
if($user && $user['pwd'] == $pwd){
if($user['status'] == 1){
$action = 1;
}
else {
$order = 'Unauthorised';
}
}
else {
$error = 'invalid';
}
}
return array('action'=>$action,'error'=>$error,'order'=>$order);
}
The get_user function is like this::
function get_user($email){
global $cnx;
$q = $cnx->prepare("SELECT email FROM `users` WHERE email = :email");
$q->execute(array(':email' => $email));
return $q->fetch();
}
Now the jQuery is the real struggle. What I want is to submit the serialised values to this php. If the script returns an action of 1, I want to perform another script, I want $error to go into a div called error and order into a div called $order
This hasn't worked:
function sendvars(container,linkrul,perform){
var vars = 'access=1';
$(container).find('input').each(function(){
vars += '&' + $(this).attr('name') + '=' + $(this).val();
});
$.ajax({type:'POST',url:linkrul,data:vars,success:function(results){
if(results == 1){ }
else { $(container).find('.orders').html(results).slideDown(300); }
}
});
}
-- Hashing is off for not just while we test everything.
I would do it returning json encoded arrays:
if($access_function == 'access_login_1'){
$email = $_POST['access_email'];
$pwd = $_POST['access_pwd'];
if(!$email || !$pwd){
$resp = array(
'action' => $someValue,
'order' => $someValue,
'error' => 'No Email or password provided'
);
}
else {
$user = get_user($email);
if($user && $user['pwd'] == $pwd){
if($user['status'] == 1){
$resp = array(
'action' => 1,
'order' => $someValue,
'error' => 'No Error'
);
}
else{
$resp = array(
'action' => $someValue,
'order' => 'Unauthorised',
'error' => 'Order Error'
);
}
}
else {
$resp = array(
'action' => $someValue,
'order' => 'Unauthorised',
'error' => 'Invalid'
);
}
}
echo json_encode($resp);
}
And in js:
function sendvars(container,linkrul,perform){
var vars = 'access=1';
$(container).find('input').each(function(){
vars += '&' + $(this).attr('name') + '=' + $(this).val();
});
$.ajax({type:'POST',url:linkrul,data:vars,dataType:'JSON',success:function(results){
if(results.action == 1){
//do something
}else if(results.action == someOtherValue){
$(container).find('.orders').html(results.order).slideDown(300);
}else{
alert(results.error); //Or put the error in some div
}
//any other code or if/else statement
});
}
You need to think more carefully about what data is being sent from the PHP to the AJAX callback:
Remember that a PHP script cannot "return" anything, it simply "displays" it. So return array('action'=>$action,'error'=>$error,'order'=>$order); will not produce any output that the Javascript can read unless you then serialize it (turn it into a string and output it) in some way, such as XML or JSON (using json_encode()). You can test that the script is outputting something useful by looking at it directly in your browser, or using debug tools such as Firebug.
jQuery needs to know what encoding you've output your data in (see documentation on the dataType parameter). If it's XML, it will pass the whole XML document to your callback function, so you would need to use functions like .find and .each to inspect it. Probably the easiest is for your PHP to use header('Content-type: application/json'); (which tells jQuery you're using JSON) and echo some data using json_encode, so that your Javascript callback gets a simple Javascript object to work with.
Your current Javascript assumes that the result of the AJAX call is either an integer (result == 1) or a blob of HTML .html(results). A better approach would be to pass back the whole result structure shown in your PHP code (i.e. echo json_encode(array('action'=>$action,'error'=>$error,'order'=>$order));). Then you can check and act on each part of the structure separately (e.g. response.action == 1, .html(response.order)), and your code becomes more readable and more flexible for future situations.
Finally, jQuery has some built-in functions which can do some more of your work for you here: check out $.post as a short-hand for the AJAX call, and .serialize() (or its cousin .serializeArray()) for reading out the current values of form elements in a form you can send to the AJAX callback.
(Incidentally, I'm sure you'd have spotted this, but I presume linkrul should be linkurl)
This is also one option.
HTML
<input type='text' class='email' />
<input type='password' class='pass' />
PHP - checkLogin.php
<?php
$action = 0;
$order = 0;
$error = 0;
if(isset($_POST['email'], $_POST['pass'])) {
if(!empty($_POST['email']) && !empty($_POST['pass'])) {
$user = get_user($email);
if($user && $user['pwd'] == $_POST['pass']){
if($user['status'] == 1){
$action = 1;
} else {
$order = 'Unauthorised';
}
} else {
$error = 'invalid';
}
} else {
$error = "Empty";
}
$array = array('action'=>$action,'error'=>$error,'order'=>$order);
echo json_encode($array);
}
Javascript
function checkLogin(){
var email = $('.email').val();
var pass = $('.pass').val();
$.post('checkLogin.php', {email:email,pass:pass}, function(response) {
var result = $.parseJSON(response);
if(response['action'] == 1) {
//authorized
} else if(response['order'] == 'Unauthorised') {
//unauthorized
} else {
//error
}
});
}
Related
I have never done combining ajax and session before. So far i have done something like this.
var sessionvar;
$.ajaxSetup({cache: false})
$.get('test.php' ,function (data) {
sessionvar = data;
alert(sessionvar);
var checkedCbs = $('sessionvar:checked');
if (checkedCbs.length === 4) {
alert("You can only select 3 books");
this.checked = false;
}
});
I want to try set the limitations based on session. Inside the test.php i have something like this
<?php
session_start();
if(isset($_POST['sBorrow']) && $_POST['action']){
if(isset($_SESSION['sBorrow']) && is_array($_SESSION['sBorrow'])){
$sborrow = $_POST['sBorrow'];
$set = $_SESSION['sBorrow'];
}
else{
$set = array();
}
if($_POST['action'] == "SET"){
array_push($set, $_POST['sBorrow']);
$_SESSION['sBorrow'] = $set;
}
else if($_POST['action'] == "UNSET"){
$unset = $_SESSION['sBorrow'];
if(($key = array_search($_POST['sBorrow'], $unset)) !== false) {
unset($unset[$key]);
$_SESSION['sBorrow'] = $unset;
}
}
}
//session_destroy();
if(isset($_SESSION['sBorrow'])){
$countses = count($_SESSION['sBorrow']);
echo $countses;
}
// nothing requested, so return all values
print json_encode($_SESSION);
?>
Inside these i have create some array to store something. Never mind that, i just want to know how to run an ajax with session. Im not sure if my codes is right for implementing that.
I'm trying to create a username availability check. I don't seem to be getting a response back though. I don't get any errors in the console, just the 200 OK but with no response, which should be the $result?
php:
if(isset($_POST['signusername']) && !empty($_POST['signusername'])){
$signusername= $_POST['signusername'];
$result='';
if(checkUsername($signusername, $conn) == TRUE){
$result='user found';
}else{
$result='user not found';
}
echo $result;
}
jquery:
$.post('username_check.php', { signusername: username }, function (result)//not getting this back
{
if (result == 'user not found')
{
$('.error').text('Avaliable');
} else if (result == 'user found')
{
$('.error').text('Taken');
}
});
If I change the 'else if' to an 'else' it will work and display 'taken', if i change result='' it still doesn't work.
Anyone know what I'm doing wrong?
edit-
function checkUsername($signusername, $conn) {
$stmt = $conn->prepare("SELECT * FROM user_info where username= '".$signusername."'");
$stmt->bindParam(1, $signusername);
$stmt->execute();
if($stmt->rowCount() == 1) {
return TRUE;
}
};
This is the function for checking the username, I also use it for checking if the username is taken after the form has been submitted, it works fine. Maybe the problem lies with this function?
PHP:
if(isset($_POST['signusername']) && !empty($_POST['signusername'])){
$signusername= $_POST['signusername'];
$result='';
if(checkUsername($signusername, $conn) == TRUE){
$found = true;
} else {
$found = false;
}
echo json_encode(array('userFound' => $found));
}
JS:
$.post('username_check.php', { signusername: username }, function (data) {
if (data.userFound == false) {
$('.error').text('Avaliable');
} else if (data.userFound == true) {
$('.error').text('Taken');
} else {
$('.error').text('Error checking for username avaliablility');
}
}, 'json')
.error(function(e){
console.log(e); // Look at your JS console for more info
$('.error').text('Error checking for username avaliablility');
});
This is a common issue when trying to compare AJAX responses directly, there is almost always hidden or special characters making a direct comparison difficult at best. Instead wrap your response in XML or JSON, not only will it look cleaner it will be easier to manage.
$_GET['numberofwelds']; & $_GET['numberofconwelds']; are sent to this script using GET JSON. I want to add these together, and then use json_encode to send a total back to the callback (in another php script) . If both $_GET 's are empty, then I want nothing to happen. How should I change this?
$numberofwelds = $_GET['numberofwelds'];
$numberofconwelds = $_GET['numberofconwelds'];
if (isset($_GET['numberofwelds']) && $_GET['numberofwelds'] != '' {
$numberofwelds + $numberofconwelds = $sum_total;
echo json_encode($sumtotal);
} else {
exit()
}
Firstly, you are trying to access your $_GET variables without checking they exist first.
Secondly, you should be throwing Exceptions instead of just calling exit() or die(). You can then log them with $e->getMessage() or write them to the local filesystem.
Finally, you need to validate your data. Make sure it is what you expect it to be.
if (isset($_GET['numberofwelds']) && isset($_GET['numberofconwelds']))
{
// Now we know both values definitely exist, VALIDATE them
$numwelds = $_GET['numberofwelds'];
$numconwelds = $_GET['numberofconwelds'];
if (is_int($numwelds) && is_int($numconwelds))
{
// Calculate your total
$total = $numwelds + $numconwelds;
echo json_encode($total);
}
else
{
// We get here because your GET variables do exist but they aren't
// numbers as you expect (you or someone else has sent rubbish data)
// You want to do nothing, although I would return an error in your json
// to be displayed to the user or logged by the consumer of the service
}
}
else
{
// We get here because your GET variables simply don't exist. They haven't been
// passed in as you are expecting them to be
// You want to do nothing, although I would return an error in your json
// to be displayed to the user or logged by the consumer of the service
}
Always code defensively.
I'm going to show you what I would do in this situation.
if (isset($_GET['numberofwelds']) && isset($_GET['numberofconwelds']))
{
$numwelds = $_GET['numberofwelds'];
$numconwelds = $_GET['numberofconwelds'];
if (is_int($numwelds) && is_int($numconwelds))
{
$total = $numwelds + $numconwelds;
$response = array("status" => "success", "message" => $total);
echo $response;
}
else
{
$response = array("status" => "failure", "message" => "GET params were not numbers");
echo $response;
}
}
else
{
$response = array("status" => "failure", "message" => "GET params do not exist");
echo $response;
}
Then, in your consuming service (most likely a JavaScript / jQuery AJAX call), you can do the following:
.done(function(data) {
var json = $.parseJSON(data);
if (data.status === "success") {
// Yay, we got a success back
console.log("The total is: " + data.message);
} else if (data.status === "failure") {
// Uh oh, something's gone wrong server-side
console.log(data.message);
}
});
change this
if ($_GET['numberofwelds'] != '' && $_GET['numberofconwelds'] != '') {
$numberofwelds + $numberofconwelds = $sum_total;
echo json_encode($sumtotal);
} else {
exit()
}
to this
if ($numberofwelds && $numberofconwelds ) {
$sum_total = array(
'sumTotal' => $numberofwelds + $numberofconwelds,
);
echo json_encode($sum_total);
}else {
exit();
}
Please always check existence of the array keys with isset() construction or array_key_exists() function.
if (isset($_GET['numberofwelds']) && $_GET['numberofwelds'] != '' && isset($_GET['numberofconwelds']) && $_GET['numberofconwelds'] != '') {
echo json_encode(array("total" => $_GET['numberofwelds'] + $_GET['numberofconwelds']));
} else {
exit();
}
UPDATE
With is_numeric() function this code should be more robust:
if (isset($_GET['numberofwelds']) && is_numeric($_GET['numberofwelds']) && isset($_GET['numberofconwelds']) && is_numeric($_GET['numberofconwelds'])) {
echo json_encode(array("total" => $_GET['numberofwelds'] + $_GET['numberofconwelds']));
} else {
exit();
}
PHP reference: array_key_exists()
PHP reference: isset()
$numberofwelds = json_decode($_GET['numberofwelds'], true);
$numberofconwelds = json_decode($_GET['numberofconwelds'], true);
$mergedJson = array_merge(numberofwelds, numberofconwelds);
echo json_encode($mergedJson);
This should do it. It grabs the json, decodes and turns it in to an array (second parameter of json_decode set to true) and then combines them.
I'd like some help please, if its possible.
I have created two functions in order to display some messages when is set a $_GET after a redirect.Here's the code:
function display(){
if(isset($_GET['cnf_upd']) && $_GET['cnf_upd'] == '1'){
$value = "The update was successful!";
$type = "confirm";
construct_the_div($value, $type);
}
if(isset($_GET['err_upd']) && $_GET['err_upd'] == '1'){
$value = "The Update failed.";
$type = "error";
construct_the_div($value, $type);
}
if(isset($_GET['cnf_del']) && $_GET['cnf_del'] == '1'){
$value = "Deleted completely.";
$type = "confirm";
construct_the_div($value, $type);
}
if(isset($_GET['err_del']) && $_GET['err_del'] == '1'){
$value = "Unable to delete.";
$type = "error";
construct_the_div($value, $type);
}
}
function construct_the_div($value, $type){
// creating a div to display the message results
$div = "<div class=\"{$type}Msg\">\n";
$div .= "<p>{$value}</p>\n";
$div .= "</div><!-- end of {$type}Msg -->\n";
echo $div;
}
What I'd like to make is to try to improve the display function, as it gets longer and longer, so that there whould be only one (or two at most) if statement(s) if possible. So the value of the GET will be dynamicly inside the if condition and also if it has the preffix 'cnf_' it wil be a 'confirmMsg' and if it has the preffix 'err_' it wil be a 'errorMsg'.
Is it possible to make something like this???
function display() {
$messages = array(
'cnf_upd' => 'The update was successful!',
'cnf_err' => 'The Update failed.!',
// ...
// add all error and confirm there
// ...
);
foreach($_GET as $key => $value) {
if(strpos($key, 'cnf_')===0) {
$type = 'confirm';
$value = isset($messages[$key])
? $messages[$key]
: $key;
construct_the_div($value, $type);
}
if(strpos($key, 'err_')===0) {
$type = 'error';
$value = isset($messages[$key])
? $messages[$key]
: $key;
construct_the_div($value, $type);
}
}
}
The approach is not correct, it seems that only one message should occur at once (there cannot be "deleted completely" and "unable to delete" at once).
Try construct the parameters this way: ?msg=upd&msgType=cnf
function display(){
if (isset($_GET['msg']) && isset($_GET['msgType']))
{
$messages = array('cnf_upd'=>'The update was successful!',
'err_upd'=>'The update failed!',
'cnf_del'=>'The deletion was successful!',
'cnf_upd'=>'The deletion failed!',
);
if (isset($messages[$_GET['msgType'].'_'.$_GET['msg']))
construct_the_div($messages[$_GET['msgType'].'_'.$_GET['msg']], htmlspecialchars($_GET['msgType']));
}
there is still much to improve, but for start this is cleaner and safer.
I'm going to propose a different solution. Instead of setting different parameters in $_GET based on the message to be sent, set one parameter and parse its value.
// Start by setting integer constants:
define(CNF_UPD, 1);
define(ERR_UPD, 2);
define(CNF_DEL, 3);
define(ERR_DEL, 4);
Then when you set the value un $_GET, use the constant:
// Build the URL with a deletion error...
header("Location: http://example.com/script.php?msg=" . ERR_DEL);
Finally, use a switch to parse them
if (isset($_GET['msg'])) {
switch ($_GET['msg']) {
case CNF_UPD:
// Updated...
break;
case ERR_UPD:
// failed...
break;
// etc...
default:
// invalid code.
}
}
If you use a pattern of confirm/error/confirm/error for your integer constants, you can determine which it is by taking $_GET['msg'] % 2. Odd numbers are confirmations, evens are errors. There are of course many other ways you could lay this out, I just happen to have typed them in the alternating order you used. You could also do positive integers for confirmations and negatives for errors, for example.
$type = $_GET['msg'] % 2 == 1 ? $confirm : $error;
This is easily expanded to use multiple messages as well. Since they are integer values, you can safely construct a comma-separated list and explode() them when received.
$messages = implode(array(ERR_DEL,CNF_UPD));
header("Location: http://example.com/script.php?msg=$messages");
Unless you can somehow generate $value and $type based on the $_GET parameter (which I can't see how you would do), you could do something like:
$messages = array();
$messages[] = array('id' => 'cnf_upd', 'value' => 'The update was successful!', 'type' => 'Confirm');
$messages[] = array('id' => 'err_upd', 'value' => 'The Update failed.', 'type' => 'error');
...
foreach ($messages as $message) {
if(isset($_GET[$message['id']]) && $_GET[$message['id']] == '1'){
construct_the_div($message['value'], $message['type']);
}
}
I have 2 classes that return a json encoded array if an error message is added to the $_error array:
Validate.class.php:
public function showResponse()
{
if(!empty($this->_error)) {
return json_encode($this->_error);
}
else {
return true;
}
}
UserTools.class.php:
public function showResponse()
{
if(!empty($this->_error)) {
return json_encode($this->_error);
}
else {
return true;
}
}
Then in ajax.php I check if either of those classes return true, if so a new user can be added by a User class, then the user class will return a success response, if they don't return true, the json encoded errors in either UserTools.class.php or Validate.class.php are returned by either of those classes:
ajax.php
if($validate->showResponse() === true && $user_tools->showResponse() === true) {
$user = new User($username, $password, $email);
$user->save();
echo $user->showResponse();
}
else {
echo $user_tools->showResponse();
echo $validate->showResponse();
}
Firebug shows that everything get's returned as expected, UserTools.class.php returns the usernameexists error and Validate.class.php returns the others:
{"error":{"usernameexists":"Username already taken"}}
{"error":{"password":"This field is required","password_again":"This field is required","email":"This field is required"}}
Yet I can't display either of those messages via jQuery, if I remove 'echo $user_tools->showResponse();' from 'else' in ajax.php, the error messages do get appended correctly, when I want to display both errors, nothing get's appended.
jQuery file:
if(msg.error) {
if(msg.error['usernameexists']) {
$('#msg-username').show().html('<p></p>').addClass('error');
$('#msg-username p').append(msg.error['username']);
}
if(msg.error['username']) {
$('#msg-username').show().html('<p></p>').addClass('error');
$('#msg-username p').append(msg.error['username']);
}
if(msg.error['password']) {
$('#msg-password').show().html('<p></p>').addClass('error');
$('#msg-password p').append(msg.error['password']);
}
if(msg.error['password_again']) {
$('#msg-password_again').show().html('<p></p>').addClass('error');
$('#msg-password_again p').append(msg.error['password_again']);
}
if(msg.error['email']) {
$('#msg-email').show().html('<p></p>').addClass('error');
$('#msg-email p').append(msg.error['email']);
}
}
The reason its not working is because there are 2 seperate json objects
One way is to combine them, for that put this in your ajax.php
if($validate->showResponse() === true && $user_tools->showResponse() === true) {
$user = new User($username, $password, $email);
$user->save();
echo $user->showResponse();
}else {
$r1 = $user_tools->showResponse();
$r2 = $validate->showResponse();
if($r1 !== true && $r2 !== true){
$r1 = json_decode($r1);
$r2 = json_decode($r2);
foreach($r2['error'] as $k => $v)
$r1['error'][$k] = $v;
$r1 = json_encode($r1);
}else if($r1 === true){
$r1 = $r2;
}
echo $r1;
}
Other easier way would be to return the error object itself instead of json_encoded one from Validate.class.php and UserTools.class.php and combine them in ajax.php then output the json_encoded string. this would save the 2 json_decode calls in the above code.
Your return string contains two objects and i think that is what (rightly) confuses the json parser. Try prepending a { and appending a } to the else output, and separate the two objects with a comma