I recently posted a question about deleting multiple rows in the database and basically re-used the code to update multiple rows in the database, but now I am having issue once the database has been updated and the page refreshes it keeps loggin me out an I'm not sure why.
Here is the ajax:
function editUser(){
var url = 'edit-user.php';
var ids = document.getElementById("edit-user-id").value;
var role = document.getElementById("role").value;
var status = document.getElementById("accountStatus").value;
var data = 'userID=' + ids.toString() + '&role=' + role + '&status=' + status;
$.ajax({
url: url,
data: data,
cache: false,
error: function(e){
alert(e);
},
success: function () {
var selects = $('#users-table').bootstrapTable('getSelections');
ids = $.map(selects, function (row) {
return row.id;
});
$('#users-table').bootstrapTable('refresh', {
silent: true
});
location.reload();
}
});
}
And here is the PHP:
require("../config.php");
try{
$role = $_GET['role'];
$status = $_GET['status'];
$ids = array($_GET['userID']);
$inQuery = implode(',', $ids);
$query = 'UPDATE users SET role = :role, account_status = :status WHERE user_id IN ('.$inQuery.')';
$query_params = array(
':role' => $role,
':status' => $status
);
$stmt = $db->prepare($query);
$stmt->execute($query_params);
// Set variable message of affected rows
$count = $stmt->rowCount();
$user_updated = ''.$count.' user(s) updated successfully.';
$_SESSION['user_updated'] = $user_updated;
} catch (Exception $e){
$error = '<strong>The following error occured:</strong>'.$e->getMessage();
$_SESSION['error'] = $error;
}
I tried changing cache: true, but that didn't work. Again, I do not want to be logged out. Any ideas what I am doing wrong?
EDIT: I have narrowed it down to only happen when the page refreshes. I removed this piece of code location.reload(); from the ajax call and it does not redirect me back to the login page, but if i hit F5 or click refresh it logs me out.
This is too long for a comment:
Nothing is jumping out at me that would cause you to lose what is set in the $_SESSION['user']. Try dumping $_SESSION on each page just to keep track of it and disable the redirect for now (just put an error message or something). You can dump the array like so:
print_r($_SESSION);
Do you also know your prepared statement is broken? I don't see the point of the array or the implode for $ids and $inQuery. It should be something like:
$stmt = $db->prepare(
'UPDATE users
SET role = ?, account_status = ?
WHERE user_id = ?'
);
$stmt->execute(array($_GET['role'], $_GET['status'], $_GET['userID']));
There is no point in using IN if you only have one entry. You also aren't protecting your query from anything because you are still inserting the values into the prepare statement.
It appears that I needed to move session_start() to the top of the config.php file to make sure that it is the very first thing called on the page. Everything seems to be working ok right now.
Related
I'm working on a rating system and the html/jquery codes works well so far:
Short Example
The idea is that users can rate specific items with 1 (bad), 2 (neutral) or 3 (good). In my code, all thumbs that belong to one item share the same id, e.g.
<i class="far fa-thumbs-up fa-1.5x" data-index="0" id="0"></i>
<i class="far fa-thumbs-up fa-1.5x" data-index="1" id="0"></i>
<i class="far fa-thumbs-up fa-1.5x" data-index="2" id="0"></i>
Then, I store all ratings in 'ratedArray' using the index of the item as the place for the rating at the in the array, so for the short example the corresponding 'ratedArray' the array is
ratedArray = [1, 2, 0, 2]
(you always have to add 1 for the actual rating, so 1 in the array means 2 thumbs or neutral)
Now I want to save this array and the userID (which I just store a new one in the local storage for each visitor) to my DB with
function saveToTheDB(){
$.ajax({
url: "betrayal.php",
method: "POST",
dataType: 'json',
data: {
save: 1,
uID: uID,
ratedArray: ratedArray
}, success: function(r) {
uID = r.id;
localStorage.setItem('uID', uID);
}
});
}
So far so good but now the trouble starts due to my lack of skill (just started with web design). To my first question: I will have 17*4 = 68 items that can be rated for. Since I plan to store the ratings with a unique ID, I wanted to make the DB look like this
id | 0 1 2 3 ... 68 |
1 | 1 0 2 2 ... 0 |
2 | ... |
because I want to be able to calculate the average rating for each item to color the background depending on the average value. Does this make sense or is there a better way to store my data?
My second question is how I am able to store the array properly in the db. There should be 2 options available: create new entry if user id is not in db or update entries if user id is already in db. My current (not working) code looks like
// connect to the data base
$conn = new mysqli( 'localhost', 'root', '', 'db');
if (isset($_POST['save'])){
// ???
$uID = $conn->real_escape_string($_POST['uID']);
$rateArray = $conn->real_escape_string($_POST['ratedArray']);
// create star rating for new uID
if (!$uID) {
$conn->query( "INSERT INTO db (id, 0, 1, 2, 3, *etc*) VALUES ('$uID', '$rateArray')");
$sql = $conn->query( "SELECT ID FROM db ORDER BY ID DESC LIMIT 1");
$uData = $sql->fetch_assoc();
$uID = $uData['ID'];
// update star rating if uID already exists
} else
//???;
exit(json_encode(array('id' => $uID)));
}
Also, could I use the IP adress instead of the userID to make the rating system more reliable?
I'd be greatful, if you could give me some basic tips. Cheers,
M.
As I wrote you above, I came with a simple database schema so you can better understand how you should build your application. It will seem that is more complex than what you did, but its not. Please check it and ask if anything is unclear in comments.
Only after you understand why you should implement this basic schema from bellow, we should move to PHP and jQUERY code.
Tip: use phpMyAdmin tool as a graphical interface to manage your database.
Database logical scheme
PHP Basic Logic
<?php
// our answer will be a valid JSON
header('Content-Type: application/json');
// function that encodes our response
function respond($status, $arr = array()){
// add our status, to final answer
$arr['status'] = $status;
if ($status != 'success'){
if ($status != 'internal_server_error'){
// Specific to server side errors
header("HTTP/1.1 500 Internal Server Error");
} else {
// Specific to client side errors
header("HTTP/1.1 400 Bad Request");
}
}
echo json_encode($arr, JSON_PRETTY_PRINT);
exit();
}
if (isset($_POST['item_id'], $_POST['vote_given'])){
// validate user data
$errors = array();
if (!is_numeric(($_POST['item_id'])){
$errors['item_id'] = 'value is not numeric';
}
if (!is_numeric(($_POST['vote_given'])){
$errors['vote_given'] = 'value is not numeric';
} else {
$vote_given = (int)$_POST['vote_given'];
if ($vote_given < 0 || $vote_given > 2){
$errors['vote_given'] = 'value is outside accepted interval [0,2]';
}
}
// if there are errors, then throw them back to user
if (count($errors) > 0){
respond(
'field_validation_errors',
$errors
);
}
$item_id = $_POST['item_id'];
$user_finger_print = sha1($_SERVER['REMOTE_ADDR'].$_SERVER['HTTP_USER_AGENT'])
// At this point we have three numeric values to work with
// item_id, vote_given, user_fingerpint
// SQL logic
$link = mysqli_connect("localhost", "my_user", "my_password", "world");
/* check connection */
$mysqli = new mysqli("localhost", "my_user", "my_password", "world");
/* check connection */
if (mysqli_connect_errno()) {
respond(
'internal_server_error',
array(
'code' => 1, // no more details as it is a security leackage
'message' => 'Ops! There is an Internal Server Error. Please come back later...'
)
);
}
// SQL query
$stmt = $mysqli->prepare("
INSERT INTO `products_votes`
(`item_id`,`user_finger_print`,`vote_given`)
VALUES
(?, ?, ?)
ON DUPLICATE KEY UPDATE `vote_given`= ?")
// DUPLICATE KEY WILL BE TRIGGERED ONLY IF YOU SET THIS RESTRICTION IN PHPMYADMIN FOR `user_finger_print` and `item_id` columns inside `items_votes` table
$stmt->bind_param("i", $item_id); // first ? (question mark) will be replaced by (i)nteger $item_id
$stmt->bind_param("s", $user_finger_print); // second ? (question mark) will be replaced by (s)tring $user_finger_print
$stmt->bind_param("i", $vote_given); // third ? (question mark) will be replaced by (i)nteger vote_given
$stmt->bind_param("i", $vote_given); // last ? (question mark) will be replaced by (i)nteger vote_given
$stmt->execute();
if ($stmt->errno){
$stmt->close();
respond(
'internal_server_error',
array(
'code' => 2, // no more details as it is a security leackage
'message' => 'Ops! There is an Internal Server Error. Please come back later...'
)
);
}
// close statement
$stmt->close();
// close sql connection
$mysqli->close();
// respond back to user
respond('success');
} else {
respond(
'error',
array(
'message' => 'POST data is missing'
)
);
}
?>
It may have a few errors, as I wrote it in Notepad++ but you should get the logic from it.
HTML code
I removed the id attribute because it was not necessary, and also added data-itemid="XXXXX" attribute to the wrapping parent. I added this information to the wrapping parent to prevent duplicating it for each <i> element.
<div class="item-vote-wrapper" data-itemid="1">
<i class="far fa-thumbs-up fa-1.5x" data-index="0"></i>
<i class="far fa-thumbs-up fa-1.5x" data-index="1"></i>
<i class="far fa-thumbs-up fa-1.5x" data-index="2"></i>
</div>
jQUERY code
I added comments inside code, so please read them.
$('body').on('click', '.far.fa-thumbs-up', function(){
let data_for_ajax = {};
// $(this) is the <i> element that was clicked
let vote = $(this).data('index');
// $(this).parent() - is the parent of this <i> element, meaning div with class "item-vote-wrapper"
let item_id = $(this).parent().data('itemid');
// Append values to our object
data_for_ajax['item_id'] = item_id;
data_for_ajax['vote_given'] = vote;
$.ajax({
url: "betrayal.php",
method: "POST",
data: data_for_ajax,
// Server returns a status code between 200 and 399
success: function(response) {
// This code will execute only when the request succeded
console.log(response);
},
// Server returns a status code between 400 and 505
// Please read this document to understand them better: https://www.tutorialspoint.com/http/http_status_codes.htm
error: function(jqXHR, textStatus, errorThrown){
console.log("An error occured. Request ended with status: " + textStatus);
console.log(jqXHR);
alert('An error occured. Open DEV tools by pressing F12 and check Console tab');
}
});
})
In the html , id of i isn't unique.
In php u don't update with insert because u generate a new id(AI), u can put a query and after a if , if find a record using a update query , dont find use a insert
I am working on a calendar where the background color of the day cells can be changed by the administrator. The change gets saved to the server. Right now, it's not working. Here's a portion of the JavaScript:
for(i=0; i<myDays.length; i++) { // Goes through each TD and creates a click event
myDays[i].addEventListener("click", function(){
if(this.classList.contains("avail")) {
this.classList.toggle("avail");
this.classList.toggle("halfy");
$.post("classChange.php", { dID: this.id, dClass: "halfy" } );
}
This is the PHP code in classChange.php:
if(isset($_POST["dID"]) ){
$stmt = $db->prepare("UPDATE original SET class=? WHERE id=?");
$stmt->bind_param("ss", $dClass, $dID);
$dID = $_POST["dID"];
$dClass = $_POST["dClass"];
$stmt->execute();
$stmt->close();
} else {
echo "Code error, dummy!";
}
Clicking on a cell correctly changes the class (and color) of the cell, but does not update the database. I'm not getting any errors. I think it must be a problem with the post() code, or the PHP code. Any advice?
You need to define the variables first before using them.
$dID = $_POST["dID"];
$dClass = $_POST["dClass"];
$stmt = $db->prepare("UPDATE original SET class=? WHERE id=?");
$stmt->bind_param("ss", $dClass, $dID);
I've built an admin page for my site, that contains numerous forms that save, update, delete data into different tables in my database.
Currently i have one PHP file for each function that does the mysql query according to my ajax post command. which is getting a bit out of control.
for example i have a file for saving a new category
$cataddname = $_POST['name'];
$area = $_POST['area'];
$shortname = preg_replace('/\s+/', '_', $cataddname);
$update_category = "INSERT INTO clet_faq_category (id, name, nickname, area) VALUES ('', '$cataddname', '$shortname', '$area')";
mysqli_query($db_connect, $update_category);
my save new category command posts to this file:
then i have a file that saves a category edit:
$cataddname = $_POST['name'];
$area = $_POST['area'];
$id = $_POST['cid'];
$shortname = preg_replace('/\s+/', '_', $cataddname);
$update_category = "UPDATE clet_faq_category SET name='$cataddname', nickname='$shortname', area='$area' WHERE id = '$id'";
mysqli_query($db_connect, $update_category);
And another one to delete a category:
$c_id = $_POST['delete_id'];
$sql_del = "DELETE FROM clet_faq_category WHERE id = '$c_id'";
$del_question = mysqli_query( $db_connect, $sql_del );
then i have an jQuery ajax call that calls the page:
function newcat(){
var id = "answer";
tinymce.execCommand('mceRemoveEditor', true, id);
var category = document.getElementById('newcategory').value;
var area = document.getElementById('area').value;
var dataString = 'name=' + category + '&area=' + area;
$.ajax({
type: "post",
url: "newcat.php?area_id=" + areaid,
data : {
'name': category,
'area': area,
'query' : query
},
cache: false,
success: function(html){
$('#category_table').html(html);
$('#cat-form').text("Category Saved");
}
});
return false;
}
And When you look at them it's pretty much the same thing it's just a mysql query running.
What i'm trying to do is streamline this a little bit, i thought about passing the entire query via ajax to my php file, but that's not an option as anyone that can see my js file will be able to figure out all my queries and table names, and all they need to do is post a query to my php page and damage my entire DB.
so my question is, is there a way to do this in a smarter way maybe creating php functions inside the same file, that has category_delete(), category_add(), category_edit() on the same file and using ajax target each one of those categories, at least all my functions and queries will be on the same spot not in multiple separate files if you know what i mean.
You can do like this create a separate class which perform options for insert delete and update. and on your ajax page call these function like this
$func = new CUD();
switch($_POST['action'])
{
case 'delete':
$func->delete($values..)
case 'update':
$func->update($values..)
case 'delete':
$func->insert($values..)
}
You can have to send extra parameter in ajax as action, this parameter specifies the action
in php
switch($_POST['action'])
{
case 'delete':
.....
}
I have a table called Stats. Stats has 4 columns: id, ip, count, and date. count is the number of clicks the ip has clicked on the ads on my site. Each time the user clicks on an ad, their count number will increase by 1. How do I increase their count number by 1 and update that in the database? Here is my code and it's not working for some reason. When I click on the div, it doesn't refresh...so the whole block of code isn't executing. Note that I've already captured the user's ip when they entered my site, this is the part where if they clicked my ad, the count is incremented and updated in the database.
<script>
$(document).ready(function()
{
$("#ad").click(function()
{
<?php
$queryTot = "SELECT `count` AS total FROM Stats WHERE ip = '$ip'";
$resultTot = $db->query($queryTot);
$data = $resultTot->fetch_assoc();
$count = $data["total"] + 1;
$insert = $db->prepare("UPDATE Stats(count) WHERE ip = '$ip' VALUES(?)");
$insert->bind_param('i', $count);
$insert->execute();
$insert->close();
?>
location.reload();
})
})
</script>
There is a lot of points to consider in your answer.
But very possibly you should use an AJAX solution to do it, and avoid every SQL queries in your HTML pages, because keeping SQL queries there definitely is not a good pratice, according all basic security and code maintenance POVs.
It is not possible to re-write your code here rightly without knowing your project structure, or even your idea, and you must take this answer as an important start point.
Basically, you must define in your server-side application a method which returns pure data, in a JSON format for example, and then use AJAX to access this method according an event (a click, for example), receive its response and modify your client-side, probably with jQuery and JS.
I hope this answer can help you.
I've written a short example for you that you could continue to build on to accomplish what you need. Here's the basic idea.
HTML
<input type="hidden" id="ip" value="<?php echo $_SERVER['REMOTE_ADDR'];?>"/>
jQuery
var ip = $('#ip').val();
$(document).ready(function(){
$('#ad').on('click',function(){
$.ajax({
type: 'POST',
url: 'ajaxUpdateDatabase.php',
data: 'ip='+ ip,
success: function(response){
console.log(response)
//send the user to the ad's page here for example
//you could use location.href='url-to-add-here';
//or if you really want to reload the page for a reason I fail to understand, use location.reload();
}
});
});
});
PHP (ajaxUpdateDatabase.php)
//please note that using UPDATE requires that there is previously an entry with this IP address.
//example using PDO...
$sql = 'SELECT * FROM stats WHERE ip = ?';
$stmt = $pdo->prepare($sql);
$stmt->execute(array($_POST['ip']));
if($stmt -> rowCount() > 0){
$sql = 'UPDATE stats SET count = count + 1 WHERE ip = ?';
$stmt = $pdo->prepare($sql);
$stmt->execute(array($_POST['ip']));
}
else{
//ip-address was not found in the database
//insert query goes here
}
I have this problem that I have multiple fields that updates a database via an AJAX-call. The AJAX call looks like this:
$(".fresheditable").fresheditor("save", function (id, parsedHtml) {
$.ajax({
url: 'save.php',
type: 'POST',
data: {
id: id,
parsedHtml: parsedHtml
}
});
});
The ID value changes depending on what element is being edited. The problem is when the update gets sent to the save.php document. How do I only run the update with the specific ID?
See my save.php:
if($_POST['id']='link')
{
$link = $_POST['parsedHtml']; //get posted data
// query
$sql = "UPDATE buttons SET linkname=? WHERE id=?";
$q = $conn->prepare($sql);
if ($q->execute(array($link,$_SESSION['button'])))
{
echo 1;
}
}
//The next if-statement could look like this:
if($_POST['id']='contactperson')
{
$contactperson = $_POST['parsedHtml']; //get posted data
// query
$sql = "UPDATE buttons SET contactperson=? WHERE id=?";
$q = $conn->prepare($sql);
if ($q->execute(array($contactperson,$_SESSION['button'])))
{
echo 1;
}
}
If more than one ID is sent to the save.php say link and contactperson both if-statements are true and the update sets the same values because the parsedHtml variable.
Is there anything I can do in save.php that can prevent this? Somehow I need to associate the correct parsedHtml with the corresponding id.
The comparison operator in PHP (as well as in Javascript) is == and not =
if($_POST["id"]=="link")
Is it because you're using single equals in your IF tests, which assigns and returns true as a value exists? Not double-equals for comparison?
E.g.
if($_POST['id']=='link')
not
if($_POST['id']='link')
One thing you can use is data attribute i mean
<span item-data="some_id">data</span> now you can select in jquery, the specific item-data from your html to update.
Use else-if structure.
if($_POST['id']='link') {
}
else if($_POST['id']='contactperson') {
}