I need to write a application that checks database from external server every 10 seconds to see if there is new data. Currently I have a javascript that checks if data has changed server by comparing two JSON (the old JSON and the new fetched from server) and if it has alerts user. But that is not what I need in this application. User should be alerted only when data is new, not when it has changed.
I was thinking that maybe I could do this with a PHP code that queries MYSQL and if query num_results is 0 loop until num_results is more than 0 when user gets notified. In this application it doesn't matter whether the new data is available for user in 0,1 second or 10 seconds, just as long as user gets it. This is how I tried to do the MYSQL check, but it isn't working:
<?php
include 'config.php';
if(isset($_GET['ID'])) {
$maxLoop = 20;
while($maxLoop--) {
$dbh = new PDO("mysql:host=$dbhost;dbname=$dbname", $dbuser, $dbpass);
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
try {
$sth = $dbh->prepare('select * from testit where id = :id');
$sth->bindParam(':id',$_GET['ID'],PDO::PARAM_INT);
$sth->execute();
if($sth->rowCount()>0) {
$results = $sth->fetchAll(PDO::FETCH_OBJ);
echo '{"key":'. json_encode($results) .'}';
exit; // Found new data, end loop and script
}
} catch(PDOException $e) {
break;
}
sleep(3);
} // end while
} // end if
So how can I alter this code to make it work, or should I just try to write some javascript that would do this? And if so, how can I check whether data is new or not, instead of just checking whether it has changed or not?
How do you record 'new' data? is there a timestamp? an auto_increment primary key field?
The easiest method for polling is to simply keep track of the last known id/timestamp and see if there's anything with a higher id/newer timestamp.
As is, your method is quite inefficient. You select ALL records in the table, forcing mysql/pdo to start fetching that data from disk, etc... then simply throw it away after getting the row count. A more efficient method is do to a select count(*) ... and checking that value. This keeps mysql from having to start fetching actual row data from disk. And on some table types (myisam in particular), a count(*) operation is VERY quick.
If you want your application to check for changes every 10 seconds, you will have to use AJAX to make asyncronous requests to a php file on the server. In the php file, you only have to select * from testit where condition=false and you will get your "new data". Here's a link from where you can learn the basics of AJAX :
http://www.w3schools.com/ajax/default.asp
Related
suppose i have a web page with PHP and HTML CSS JavaScript.
values in database are inserted through PHP.
cookies are set using PHP.
cookies are fetched using JavaScript.
cookies of the page
i have an array of subjects stored in cookies. cookies also contain index varible with initial value 0. and arraySize varible with value 9.
At the very first time i fetch the first subject
and take some form response from the user associated to that subject using POST method . when the user click the submit button . the index variable is incrementing at runtime and next subject(next value of array) is inserted in the database.
that is when user clicks the submit button , my code is first updating the subject and then insert the form data into the database.
suppose i have a subject array : subject = {'a' , 'b' , 'c'};
let form variables be subject , class .
i fill the form for subject 'a' and when click the submit button subject inserted is 'b' and class inserted is what user write.
the following JavaScript i have written for incrementing the subject(i increment the index of subject) after submitting the form :
(let say it code1.)
<script>
function incrementCookie() {
var i = document.cookie.indexOf('index');
let currentIndexValue = document.cookie[i + 6] -'0';
document.cookie='index='+(++currentIndexValue);
}
incrementCookie();
</script>
code2: (inserting form variables into the database)
if (isset($_POST['insert']))
{
$co1 = $_POST['co1'];
$co2 = $_POST['co2'];
$co3 = $_POST['co3'];
$co4 = $_POST['co4'];
$co5 = $_POST['co5'];
if($GLOBALS['cols'] == 6)
$co6 = $_POST['co6'];
else
$co6 = 0;
echo "aayush";
$sb1 = $_POST['sb1'];
$sb2 = $_POST['sb2'];
$sb3 = $_POST['sb3'];
$sb4 = $_POST['sb4'];
$sb5 = $_POST['sb5'];
$id1 = $_SESSION['id'];
$sub = $_POST['subject'];
$uname = mysqli_query($con,"select email from users where id = $id1");
$result1 = mysqli_fetch_assoc($uname);
$usersemail = $result1['email'];
$sql1 = "select email from faculty where subjectalloted = '$sub1' and section = (select section from users where id= '$id1')";
$result2= mysqli_query($con , $sql1);
$row1 = mysqli_fetch_assoc($result2);
$facultyemail = $row1['email'];
co1='$co1',co2='$co2',co3='$co3',co4='$co4',co5='$co5',co6='$co6',sb1='$sb1',sb2='$sb2',sb3='$sb3',sb4='$sb4',sb5='$sb5' where id= (select max(id) from respone)");
$sql = "INSERT INTO `respone` (`subject`,`usersemail`,`facultyemail`, `co1`, `co2`, `co3`, `co4`, `co5`, `co6`, `sb1`, `sb2`, `sb3`, `sb4`, `sb5`) VALUES ('$sub1', '$usersemail', '$facultyemail','$co1', '$co2', '$co3', '$co4', '$co5', '$co6', '$sb1', '$sb2', '$sb3', '$sb4', '$sb5')";
mysqli_query($con, $sql);
}
code3: (fetching the subject)
$data = json_decode($_COOKIE['subjectArrayCookie'], true);
$index = $_COOKIE['index'];
global $sub;
$sub = $data[$index];
$_POST['subject'] = $sub;
i have tried writing code2 before code1 so that form responses inserted into database first and then
index cookie update. but due to dynamic nature of JavaScript it increments the index cookie and
subject is updated to next subject before inserting the form variables into the database.
i am expecting that, when the user clicks the submit button firstly form data for that subject will insert into the database with their correct subject name and after then same form will open for next subject in the array.
Put your PHP database insertion code at the very top of the file—before everything else, particularly the database query. Allow it to execute first.
Here's why...
all the written code above on the same page.
And from comments:
first i have fetched the subject array from the database
then insert into the cookie
after that i created the form with the submit button
then wrote the code2(inserting into database)
then code1(iincrement index cookie).
All the PHP in the entire file is executed on the server BEFORE any Javascript is executed or HTML rendered.
The result of PHP execution creates a text file containing—ONLY—HTML and Javascript. This text file is sent to the browser. NO PHP is sent to the browser therefore NONE of the PHP is executed in the browser. Only HTML is rendered and Javascript is executed in the browser.
So the order of execution, according to the 1-5 sequence above, is:
ON THE SERVER:
PHP gets data from the database and writes the cookie instructions. (The cookie not yet registered in the browser.)
PHP writes the form HTML code to be sent to the browser. (The HTML is not yet rendered in the browser.)
Upon initial requests of the page if (isset($_POST['insert'])) is NOT executed since there is no $_POST array yet. However, when this file is requested by posting form data to it PHP inserts the posted data into the database.
The Javascript code block text is added to the text file to be sent to the browser. (Javascript is NOT executed here.)
The text file containing cookie instructions, form HTML, and Javascript cookie increment code is sent to the browser.
IN THE BROWSER:
The cookie, written in SERVER step 1, is registered.
The form HTML is rendered.
The Javascript cookie code is executed and increments the cookie.
I have a basic chat system set up that uses an SQL database and a PHP script -- when the user inputs a message, its sent to the database and then is retrieved and displayed. New messages are displayed every 5 seconds regardless.
All that being said, its fairly easy to just spam messages causing the website to stop responding at which point clicking any links will result in an error page, and no further messages will be input.
Is this a common scenario? How should I improve the chat's performance? Note: I'm really new PHP and JS/Jquery.
Here is the main script that is frequently called to update the html chatbox with new messages for the logged-in user:
Two auto-incremented values are compared to determine "new messages", the value of the last displayed message, and the value of the last message in the database.
<?php
session_start();
if (isset($_SESSION['logged_in']) && $_SESSION['logged_in'] == true) {
$alias = $_SESSION['username'];
$host = 'localhost';
$user = 'root';
$pass = '';
$database = 'vethergen_db_accounts';
$table = 'table_messages';
$user_table = 'table_user_info';
$last_id_table = 'table_chat_sync';
$connection = mysqli_connect($host, $user, $pass) or die ("Unable to connect!");
mysqli_select_db($connection,$database) or die ("Unable to select database!");
if ($redis->exists("/lastId/$alias"))
{
$last_id = $redis->get("/lastId/$alias"); //Gets the last id from cache...
}
else
{
$last_id_query = "SELECT last_id FROM $last_id_table WHERE alias = '$alias'";
$last_id_result = mysqli_query($connection,$last_id_query);
$last_id_rows = mysqli_fetch_array($last_id_result);
$last_id = $last_id_rows['last_id'];
// Now that you just read it, create a last_id cache entry for this user
$redis->set("/lastId/$alias", $last_id);
}
$query = "SELECT * FROM $table WHERE text_id > '$last_id'"; //SELECT NEW MESSAGES
$result = mysqli_query($connection,$query);
if ($result && mysqli_num_rows($result) > 0)
{
while($row = mysqli_fetch_array($result))
{
$color_alias = $row['alias'];
$text_color_query = "SELECT color FROM $user_table WHERE alias = '$color_alias'";
$text_color_result = mysqli_query($connection,$text_color_query);
$text_color_rows = mysqli_fetch_array($text_color_result);
$text_color = $text_color_rows['color'];
if ($row['alias'] === "Vether")
{
echo '<p id = "chat_text" style="color:'.$text_color.'">'.'<b>'.$row['alias'].': '.'</b>'.$row['text']."</p>";
echo '<p id = "time_stamp">'.$row['time'].'</p>';
echo '<p id = "chat_number">'.$row['text_id'].'</p>';
}
else
{
echo '<p id = "chat_text" style="color:'.$text_color.'">'.'<b class = "bold_green">'.$row['alias'].': '.'</b>'.$row['text']."</p>";
echo '<p id = "time_stamp">'.$row['time'].'</p>';
echo '<p id = "chat_number">'.$row['text_id'].'</p>';
}
echo '<hr class = "chat_line"></hr>';
$last_row_id = $row['text_id'];
}
//UPDATE LAST SYNC ID
$update_query = "UPDATE $last_id_table SET last_id = '$last_row_id' WHERE alias = '$alias'";
$redis->delete("/lastId/$alias");
mysqli_query($connection,$update_query);
}
else {echo '';}
?>
There is no specific right answer because your question is very general, but there are a few things that are obvious here. You have built a botteneck in your database where the more users you have, the more updates you are doing on the table_chat_sync.
As an aside, I have no idea why you are putting a constant (the table name) into PHP variables for your queries. At very least these should be php constants but that makes the syntax pretty painful. Your code is simpler and better just using the table names in the SQL.
InnoDB
Are you using InnoDB tables? You should be, given that you are updating a row and with InnoDB you have row level locking.
You also want to make sure that you have enough innodb buffer pool cache allocated to insure that the db is in memory. This will buffer your select activity a lot and buy you some head room.
MySQL EXPLAIN
You also need to do explain plans on your select query and insure that it is properly indexed so that the queries are being returned using indexes and you are not table scanning or having temporary tables created.
SQL queries against mysql are quite slow compared to getting data from cache, and the reality is that the full set of chat messages doesn't change much, and yet your system is repeatedly going to be querying the chat or a subset of it over and over again. For this reason, most sophisticated systems are using some sort of caching system or queuing. There is overlap between these two technologies and they tend to offer better scalability as well as support for concepts like publish/subscribe that fit chat very well.
Redis & Other backends
Redis as an example, could be the back end for chat and completely supplant the actual storage and retrieval of messages. The document database MongoDB is also an alternative option that has in-memory characteristics when the dataset can be controlled.
Using Redis with MySQL
Redis is often combined with an RDBMS and in your code there are a few places where it could be a great help. For example, you do this query repeatedly:
$last_id_query = "SELECT last_id FROM $last_id_table WHERE alias = '$alias'";
With redis you could do something like this:
if ($redis->exists("/lastId/$alias")) {
$last_id = $redis->get("/lastId/$alias");
} else {
$last_id_query = "SELECT last_id FROM $last_id_table WHERE alias = '$alias'";
$last_id_result = mysqli_query($connection,$last_id_query);
$last_id_rows = mysqli_fetch_array($last_id_result);
$last_id = $last_id_rows['last_id'];
// Now that you just read it, create a last_id cache entry for this user
$redis->set("/lastId/$alias", $last_id);
}
The only other detail is that when you update the last Id you would want to delete the redis key:
$redis->delete("/lastId/$alias");
Hopefully you can see that this would lower the load on mysql quite a bit, because no query will occur without a new message being added. This will buffer mysql quite a bit, and the same concept can be used to cache the other queries you are doing, such that you never require mysql queries unless you have a new user actively using Redis. I didn't go into this but you can set the expiration of a key to some period of time, so it will clean up old keys from non-active users.
Load Testing to understand your bottlenecks and capacity
Your choice of reliance on MySQL is something you will have to accept as limiting, although again you may be able to tune it so that within your use case and load, it runs acceptably, but that is impossible to predict without detailed configuration analysis and load testing. There are many load testing and stress testing tools that are FOSS, with Apache JMeter being one of the oldest ones, so I'll advise you to start with that.
Websockets
Last but not least, polling is inherently wasteful and most chat systems these days are built using websockets which is just a better fit for the task of having a sustained client-server connection. Websocket is client & Server code, and being that you are a PHP dev, there are a few projects that can help you out here, Ratchet being one that has been around for a while. There's a PHP client lib Pawl that shows you how to make a simple robust websocket connection.
You can add a Limit to the end of SELECT * FROM $table WHERE text_id > '$last_id' and that will keep some of the spam messages from slowing down the thread. Also you can prohibit duplicates on the INSERT statement.
I'm creating an ticket booking application. I'm trying to create a basic cart using PHP and Ajax, When i click on the add to cart button, It sends the seat number to the "seatchecker.php" file using Ajax which checks if the seat is available, Then if it's available, It sends that seat number to the "seatadder.php" file using Ajax which should add the seat number to the Session array. But each time i click "Add to cart" it just displays the new value, Rather than showing the whole cart. May be it's overwriting the session variable each time? any help would be appreciated. Thanks
<?php
session_start();
// Getting the value sent by checkseats.php using ajax
$seat_added = $_GET['seatadd'];
// ARRAY OF SESSION VARIABLE
$_SESSION['seat_add'] = array();
function multiple_seats_adder($getseat){
array_push($_SESSION['seat_add'],$getseat);
// TESTING
print_r($_SESSION['seat_add']);
// TESTING
echo sizeof($_SESSION['seat_add']);
}
echo multiple_seats_adder($seat_added);
?>
The Problem seems to stem from the Fact that you are initializing the seat_add Key to an Empty Array each time the Script is called. Most likely, that is not what you want. Consider the Code below:
<?php
session_start();
// Getting the value sent by checkseats.php using ajax
$seat_added = $_GET['seatadd'];
// ONLY INITIALIZE THIS TO AN EMPTY ARRAY IF IT DOESN'T EXIST AT ALL:
if(!isset($_SESSION['seat_add'])){
// ARRAY OF SESSION VARIABLE
$_SESSION['seat_add'] = array();
}
function multiple_seats_adder($getseat){
array_push($_SESSION['seat_add'], $getseat);
// TESTING
print_r($_SESSION['seat_add']);
// TESTING
echo sizeof($_SESSION['seat_add']);
}
multiple_seats_adder($seat_added);
I am here to ask you about a PHP file I've been coding. I am building a live auction website that lets the users take part to auctions, each one shown in a site's page. In order to let users know when someone else has made a bid, I have used a SSE system. I use AJAX for the user's bid action's registration on the database (when the user bids, the price of the item in the database gets higher to exactly 1 dollar more. The price is stored as current price + 100 in the database because I am only storing integers (the number of cents) for the prices, for security reasons).
My AJAX works well, so the bid actually happens.
My SSE connection gets opened as expected, at the moment of the page load. The javascript EventSource object successfully opens the stream to my PHP file, but I can't understand why, when I make a test bid in the auction's page using my AJAX, the PHP SSE worker doesn't send a message to the auction's page (that has opened the stream to the worker).
Here is the PHP code that is supposed to check whether there's a new bid and send a message to the auction's page containing the new bid's data.
<?php
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
$mysqli = new mysqli(* data *);
$listings = $mysqli->query("SELECT listing_id, price, buyer_id FROM listings WHERE schedule_requested = '1' AND finished = '0'");
$to_check = array();
while ($li = $listings->fetch_array()) {
$to_check[] = array($li["listing_id"], $li["price"], $li["buyer_id"]);
}
while (true) {
$change = 0;
$listings_2 = $mysqli->query("SELECT listing_id, price, buyer_id FROM listings WHERE schedule_requested = '1' AND finished = '0'");
$different = array();
while ($li_2 = $listings_2->fetch_array()) {
foreach ($to_check as &$li_check) {
if ($li_check[0] === $li_2["listing_id"]) {
if (intval($li_2["price"]) !== intval($li_check[1])) {
$li_check = array($li_2["listing_id"], $li_2["price"], $li_2["buyer_id"]);
$different[] = $li_check;
$change = 1;
}
break;
}
}
}
if ($change === 1) {
echo "data: " . json_encode($different) . PHP_EOL;
echo PHP_EOL;
flush();
}
sleep(1);
}
?>
I hope you can follow how I reasoned to write this code: when the connection is opened, all the listings (that are the lots the auction is composed of) that are eligibile for taking part in the auction will be checked and stored in the array called $to_check. Every time the outer while loop iterates, the code sends a query to the database again to check if some price fields have been changed. In case it has happened, the code sends a message to the auction's page, in order to inform the user.
The problem is that, when I try to bid from the auction's page, the bid is successful but I do not receive any message from the PHP worker (that is supposed to tell me that the x listing price has changed). What is the problem with that PHP code?
Thanks for your help.
P.S. For clarity reasons, I will also write the Javascript code that handles the SSE system.
<script type = "text/javascript">
var evtSource = new EventSource("bidchecker.php");
evtSource.onmessage = function(e) {
console.log("onmessage");
// etc.
}
</script>
I have this datatable which gets its data from a server. The problem now is that the database contains a bit more data than i first imagined it would. So for keeping the browser from loading all entries i've created a multiple select list that I will use for only pulling out the essential information.
The input from this list is then matched with what's in the database. The result of that is then stored in $results as can be seen below.
The problem here is that i have no idea how to get the input data, especially if its multiple choice, to go in to the last mysql query which then go into $results.
Later on I use $results for pushing out data to a table. Though as i said it gets a bit crowded in the table when i load all my data into $results.
Everything else is working properly and I get my scopeIDs in my multiple select list.
So, how do I get my selected option/s to go in to
<?php
$results = mysql_query("SELECT * FROM tableID LIKE (/*some cool way of putting the input here*/)";
?>
Complete Code for the task:
///Connection parameters above///
$multiplechoice = mysql_query("SELECT scopeId FROM tableID");
$storeArray = array();
print"<select multiple name=\"scopeValues\" id=\"scopeIdchoice\">";
while ($rowchoice = mysql_fetch_array($multiplechoice, MYSQL_ASSOC)) {
$storeArray = $rowchoice['scopeId'];
print"<option id='".strtolower($storeArray)."'>";
print $storeArray;
print"</option>";
}
<?php
$results = mysql_query("SELECT * FROM tableID LIKE (/*some cool way of putting the input here*/)";
?>
Change the name of the select to scopeValues[].
From the select you will get an array of values in the $_POST array. You might pass that as a list of values to the SQL query like below. You need to adopt the xx_thefield_xxto the proper column name and of course need to do checks against SQL-injection, which are missing for better reading over here.
<?php
$scopeVals = $_POST['scopeValues[]'];
// … remember to sanitize $scopeVals before the next step
$results = mysql_query("SELECT * FROM tableID where xx_thefield_xx in ('" .
implode("','", $scopeVals) . "');";
?>
Because there is more than one value associated with a input now you need to tell the server to store all values in a array (notice the brackets):
name=\"scopeValues[]\"
Then you implode the array and run the SQL. I'll assume that you're POSTing the form data:
$scopeValues = implode(',', $_POST['scopeValues']);
// … remember to sanitize $scopeValues before the query
$results = mysql_query("SELECT * FROM tableID WHERE scopeId IN ($scopeValues) )";
Make sure to sanitize all the values in $scopeValues before interpolating them into the query to protect against SQL Injection. A more secure way would be not to use ext/mysql (it's deprecated anyway) and use PDO or ext/mysqli and use prepared statements.
(Are the IDs strings?)
I don't know if you knew this, but PHP is executed on the server. Requesting your pages goes as follows:
A browser sends a request to your server;
The server executes the PHP;
The server sends the output to the browser;
The browser renders the HTML.
This poses a problem: if you change your selection (which happens in the browser), the PHP has already been executed. It can't magically change its output that got sent to the browser. So to refresh the result, you should make a form and POST the input to the same page, which would check if data had been posted, if it had, output only the selected data, if it hadn't, show everything. If you want to make it a bit more complicated (but more usable too), you could use AJAX to retrieve the results of the select query.
The other answers covered the form already, the AJAX way would be like this:
Have a separate page which SELECTs the data using the POSTed input to filter.
Make an AJAX request (on the page that displays the data) every time the <select> changes.
(Maybe this answer is totally useless to you because you already knew PHP is server-side.)