I am a math teacher who has built an online testing site for my school to use (aka, not a pro). The site has worked well but as the amount of usage at my school increases I am starting to run into memory problems (I think). After I have about 50 to 60 users simultaneously using the site the whole website begins to crash, it will come back up after a few minutes. I never have this problem with low usage. The page where students take their quiz loads 10 questions on the page, each multiple choice with 4 radio options. (Not a lot of jquery going on). Each time the user clicks an answer I am using ajax to store their answer in the database. Below is the jquery code that sends their clicks as they take the quiz.
$('input:radio').click(function(){
var questionId = $(this).parent().parent().find('.qid').val();
var answer = $(this).val();
$.ajax({
type: "POST",
url: "insertqanswerajax.php",
data: {questionId: questionId, answer: answer},
});
});
When I load system process in my cpanel I see there are 5 different processes running, each around 80 megabytes. The maximum in my php.ini is set to 540MB. If I check the page with memory_get_peak_usage() it never reads above about half a megabyte, however in the console timeline I can see the memory usage is almost up to 10 megabytes for one user (images below). What do I need to check, or what is the best way to troubleshoot the discrepancy? What could be causing the problems? I can provide more information if needed, I am just not sure what all is relevant.
Thanks ahead of time for your help.
Here is the code for the php file accessed via ajax
<?php session_start();
include('../includes/startup.php');
$questionId = $_POST['questionId'];
$answer = $_POST['answer'];
insertQuizAnswer($questionId, $userId, $answer, 1);
?>
The function called in that file:
function insertQuizAnswer($questionId, $userId, $answer, $testId){
global $DB;
$standardsHandle = $DB->prepare("INSERT INTO quizanswers (questionid, userid,answer,testid)
VALUES (:questionId,:userId, :answer, :testId)
");
$standardsHandle->bindParam(':questionId', $questionId);
$standardsHandle->bindParam(':userId', $userId);
$standardsHandle->bindParam(':answer', $answer);
$standardsHandle->bindParam(':testId', $testId);
$standardsHandle->execute();
}
And the startup file loaded on both:
<?php
if(preg_match('/(?i)msie [2-7]/',$_SERVER['HTTP_USER_AGENT']))
{
// if IE < 8
echo "My Class Progress does not Work with this version of Internet Explorer</br>
<a href='https://www.google.com/intl/en/chrome/browser/'>Click Here to Download a more modern browser</a>";
exit;
}
else
{
}
if(isset($_POST['getGrade'])){
$_SESSION['gradeLevel'] = $_POST['getGrade'];
}
if(isset($_POST['getSubject'])){
$_SESSION['subject'] = $_POST['getSubject'];
}
include_once('../functions/userfunctions.php'); //all functions
include_once('../functions/goalfunctions.php'); //all functions
include_once('../functions/modulefunctions.php'); //all functions
include_once('../functions/globalfunctions.php'); //all functions
include_once('../functions/skillfunctions.php'); //all functions
include_once('../functions/quizfunctions.php'); //all functions
include_once('../functions/practicefunctions.php'); //all functions
include_once('../functions/benchmarkfunctions.php'); //all functions
include_once('../functions/dockfunctions.php'); //all functions
include_once('../functions/dashboardfunctions.php'); //all functions
include_once('../functions/notificationfunctions.php'); //all functions
include_once('../includes/connect.php'); //connect to database
$userSubject = $_SESSION['subject'];
$userGradeLevel = $_SESSION['gradeLevel'];
$userId = $_SESSION['userId'];
if ($_SESSION['loggedIn'] == 'true'){
}
else{
header('location: ../../index.php');
die();
}
?>
Here is the connect.php file that is accessed:
try {
$DB = new PDO("mysql:host=$host;dbname=$dbname", $user, $pass);
}
catch(PDOException $e) {
echo $e->getMessage();
}
The amount memory used is dependent on ini_set('memory_limit'); This amoutn is reserved by Apache, it doesn't matter how much the script actually uses until it runs out of memory.
Related
I'm writing a php web application hosted on iis web server and i'm actually trying to make a read-only powershell live web console.
This is how it works:
1) in my "console" main page i have a div and some buttons, the div starts empty
2) when you click a button, the click generates an ajax call to a page called "engines.php" and starts to load into my div the content of "engine515data.php"
3) "engines.php" first runs a query to delete some records from a XXX table, then runs a powershell script located on a remote server
4) this powershell script replaces some files (.dll etc...) on many different remote servers and inserts some records in the same XXX table
5) "engine515data.php" runs a select from the table updated by powershell script and echoes every row
Web app is running on IIS 10 with PHP 7.3
Ajax call in my main page:
$(document).ready(function() {
$('#515S').on('click', function(){
var version = $(this).attr('version');
$.ajax({
type:'POST',
url:'engines.php',
data: {runEngine: 1, version: version},
async:true,
success:function(data){
}
});
var interval = setInterval(function () {
$('#show').load('engine515data.php');
$('#clearConsole').on('click', function(){
$("#show").html("Console is ready and waiting for a script to be executed...");
clearInterval(interval);
});
}, 1000);
});
});
Engines.php:
function runEngine($version){
$username = $_SESSION['username'];
$db_server_name = "DB_SERVER_NAME";
$remote_db_name = "DATABASE_NAME";
$conn2 = dbconn2($db_server_name,$remote_db_name);
$query="DELETE FROM XXX WHERE VERSION = '$version' AND UPD_TYPE = 'YYY' AND USERNAME = '$username'";
if($conn2){
$handle = sqlsrv_query($conn2, $query) or die( print_r( sqlsrv_errors(), true));
}
$psPath = "C:\\WINDOWS\\system32\\WindowsPowerShell\\v1.0\\powershell.exe";
$psDIR = "\\\\SERVER_NAME\\XXX\\XXX\\";
$psScript = "SCRIPT_NAME.ps1 $version $username";
$runScript = $psDIR. $psScript;
$runCMD = $psPath." ".$runScript." 2>&1";
$output = shell_exec($runCMD);
}
if(isset($_POST["runEngine"]) && $_POST["runEngine"]=='1'){
runEngine($_POST["version"]);
}
engines515data.php:
$username = $_SESSION['username'];
$server_name = "DB_SERVER_NAME";
$remote_db_name = "DB_NAME";
$conn2 = dbconn($server_name,$remote_db_name);
$query="SELECT Message FROM XXX WHERE (Version = 515) AND (UPD_TYPE = 'YYY') AND (USERNAME = '$username')";
if($conn2){
$handle = sqlsrv_query($conn2, $query) or die( print_r( sqlsrv_errors(), true));
}
while ($row = sqlsrv_fetch_array($handle, SQLSRV_FETCH_ASSOC)) {
if((strpos($row['Message'], "AAA"))!== false ||
(strpos($row['Message'], "BBB"))!== false ||
(strpos($row['Message'], "CCC"))!== false)
echo '<font color="yellow">' . $row['Message'] . "</font>" . '<br>';
else
echo $row['Message'] . '<br>';
}
It worked with no problems until monday, then i suddently faced long response time and no more "live" records into my div.
The POST method to engines.php now take 90376ms (TTFB) to run and returns
500 - Internal server error
(after ajax call end i see what i expect into my div) but looking on SQL the .ps1 script runs smoothly, i see records i'm expecting.
I've tried to run the script directly from Powershell console while the div was refreshing and all runs smoothly with "live" records and no latency on respose time...
If i try to load the page that should retrieve the data from my DB (engines515data.php) while the ajax call is waiting the page continuously load showing nothing until the call ends and only then the div is filled with records and the page is loaded.
If i try to run, instead, a really light script (for loop writing "Test" 10 times) all runs with no problems.
I've also tried to remove some SQL queries and the while loop inside "engine515data.php" and to switch to an async ajax call but nothing changed.
I googled a lot and i already tried to change some config into my ini.php like "max_execution_time" or "memory_limit" and checked my iis application pool configuration but i cannot figure out what's wrong with my webapp. All i know is that THE SAME CODE was working perfectly until last week...
How can i avoid this huge response time?
Sorry for my english.
After many search i found out that this problem is related to a php session lock, so i managed to solve it by adding session_write_close(); in Engines.php between $username = $_SESSION['username']; and $db_server_name = "DB_SERVER_NAME";.
Thank everyone for trying, your effort was appreciated.
I have a button in a webapp that allows users to request a specially formatted number. When a user click this button 2 scripts run. The first that is fully functional, looks at a number table finds the largest number and increments it by 1. (This is not the Primary Key) the second script which is partially working gets the current date and runs a SQL query to get which period that date falls in. (Periods in this case not always equaling a full month) I know this script is at least partially working because I can access the $datetoday variable called in that script file. However it is not returning the requested data from the periods table. Anyone that could help me identify what I am doing wrong?
<?php
include 'dbh.inc.php';
$datetoday = date("Ymd");
$sql = "SELECT p_num FROM periods where '$datetoday' BETWEEN p_start AND p_end";
$stmt = mysqli_stmt_init($conn);
if(!mysqli_stmt_prepare($stmt, $sql)) {
header("Location: ../quote.php?quotes=failed_to_write");
exit();
} else {
mysqli_stmt_execute($stmt);
mysqli_stmt_store_result($stmt);
$result = mysqli_stmt_get_result($stmt);
$row = mysqli_fetch_assoc($result);
$pnum = $row;
mysqli_stmt_close($stmt);
}
If it helps any one I published my code to https://github.com/cwilson-vts/Quote-Appliction
So first off, I do not use msqli and never learned it. However, I believe I get the gist of what you want to do. I use PDO because I FEEL that it is easier to use, easier to read and it's also what I learned starting off. It's kinda like Apple vs. Samsung... no one product is exactly wrong or right. And each have their advantages and disadvantages. What I'm about to provide you will be in PDO form so I hope that you will be able to use this. And if you can't then no worries.
I want to first address one major thing that I saw and that is you interlacing variables directly into a mysql statement. This is not considered standard practice and is not safe due to sql injections. For reference, I would like you to read these sites:
http://php.net/manual/en/security.database.sql-injection.php
http://php.net/manual/en/pdo.prepared-statements.php
Next, I'm noticing you're using datetime as a variable name. I advise against this as this is reserved in most programming languages and can be tricky. So instead, I am going to change it something that won't be sensitive to it such as $now = "hello world data";
Also I'm not seeing where you would print the result? Or did you just not include that?
Another thing to consider: is your datetime variable the same format as what you are storing in your db? Because if not, you will return 0 results every time. Also make sure it is the right time zone too. Because that will really screw with you. And I will show you that in the code below too.
So now on to the actual code! I will be providing you with everything from the db connection code to the sql execution.
DB CONNECTION FILE:
<?php
$host = '127.0.0.1';
$user = 'root';
$pw = '';
$db = 'test'; // your db name here (replace 'test' with whatever your db name is)
try {
// this is the variable will call on later in the main file
$conn = new PDO("mysql:host=$host;dbname=$db;", $user, $pw);
} catch (PDOException $e) {
// kills the page and returns mysql error
die("Connection failed: " . $e->getMessage());
}
?>
The data file:
<?php
// calls on the db connection file
require 'dbconfig.php';
// set default date (can be whatever you need compared to your web server's timezone). For this example we will assume the web server is operating on EST.
date_default_timezone('US/Eastern');
$now = date("Ymd");
// check that the $now var is set
if(isset($now)) {
$query = $conn->prepare("SELECT p_num FROM periods WHERE p_start BETWEEN p_start AND :now AND p_end BETWEEN p_end AND :now");
$query->bindValue(':now', $now);
if($query->execute()) {
$data = $query->fetchAll(PDO::FETCH_ASSOC);
print_r($data); // checking that data is successfully being retrieved (only a troubleshooting method...you would remove this once you confirm it works)
} else {
// redirect as needed and print a user message
die("Something went wrong!");
}
$query->closeCursor();
}
?>
Another thing I want to mention is that make sure you follow due process with troubleshooting. If it's not working and I'm not getting any errors, I usually start at the querying level first. I check to make sure my query is executing properly. To do that, I go into my db and execute it manually. If that's working, then I want to check that I am actually receiving a value to the variable I'm declaring. As you can see, I check to make sure the $now variable is set. If it's not, that block of code won't even run. PHP can be rather tricky and finicky about this so make sure you check that. If you aren't sure what the variable is being set too, echo or print it with simply doing echo $now
If you have further questions please let me know. I hope this helps you!
I think I know what I was doing wrong, somebody with more PHP smarts than me will have to say for sure. In my above code I was using mysqli_stmt_store_result I believe that was clearing my variable before I intended. I changed that and reworked my query to be more simple.
<?php
include 'dbh.inc.php';
$datetoday = date("Ymd");
$sql = "SELECT p_num FROM periods WHERE p_start <= $datetoday order by p_num desc limit 1";
$stmt = mysqli_stmt_init($conn);
if(!mysqli_stmt_prepare($stmt, $sql)) {
header("Location: ../quote.php?quotes=failed_to_write");
exit();
} else {
mysqli_stmt_execute($stmt);
$result = mysqli_stmt_get_result($stmt);
while( $row = mysqli_fetch_assoc($result)) {
$pnum = $row['p_num'];
echo $pnum;
}
mysqli_stmt_close($stmt);
}
Thanks to #rhuntington and #nick for trying to help. Sorry I am such an idiot.
I want to update a MySQL field after when the site was opened for X Seconds.
I get the Seconds/Time from MySQL and want to update in MySQL when the seconds are over.
I tried
sleep($adddisplaytime);
but then the site waits complete and does not run the things over first
Is there a way to run my update after some seconds when the site is opened?
$query1 = "UPDATE ads SET views = views+1, costs = costs+price WHERE id = '".$adid."'";
Can be in PHP or MySQL
NOTE: This will do what you want, but could be exploited by someone hitting the AJAX endpoint repeatedly, you would want to build in some protections for that.
You will need an additional PHP file, the job of that PHP is to only update the db. You will need to take that update OUT of your page loading script.
Your HTML / JS / PHP for initial load
<script>
setTimeout(function() {
$.ajax('/your/ajax/endpoint.php', {
data: {
'adid': 'your id'
/*
If this is in your PHP file, you can echo the ID straight there.
Not totally recommended, but that's one way An additional /
better way is to add it to a div with a data attribute and
use jQuery to select the data off of there
*/
}
}); // Probably lots more you can do here, but in this case, for simplicity, just sending and that's it
}, 2000); // This will do a 2 second wait
</script>
Your new additional PHP file that is at /your/ajax/endpoint.php
<?php
// THIS FILE DOES THE UPDATE
$adid = $_POST['adid'];
// As mentioned by tadman in his comment.. I would use prepared statements
$query1 = "UPDATE ads SET views = views+1, costs = costs+price WHERE id = ?";
try {
$dbh = new PDO($dsn, $user, $password);
$sth = $dbh->prepare($query1);
$sth->execute(array($adid));
} catch (PDOException $e) {
echo 'Connection failed: ' . $e->getMessage();
}
NOTE:
Again, for security's sake, you really want to consider having your first PHP script generate a unique ID (and store it in the db), that is passed to the page, and having the AJAX send that unique ID with the adid, and if the unique ID you gave is in the database only THEN would you know it's a legitimate request. Remove the unique ID from the database and do the update.
If you want to wait for some seconds after a page is opened and then run the update statement , then write the following codes on the top of the page:-
echo "<script> setTimeout(function(){}, 2000) ; </script>" ;
$query1 = mysqli_query($con, "UPDATE ads SET views = views+1, costs = costs+price WHERE id = '".$adid."'");
I'm making a movie rating website for a project and how to do the rating system has left me at a blank. Please let me know of a proper way to this if you know.
This gets the movie number from the url and displays the relevant information in the page
<body>
<?php
global $conn;
$conn = mysqli_connect('localhost','root','','filmsdb');
function show()
{
global $film;
global $conn;
$film = $_GET['fm'];
$sql = "SELECT * FROM movies WHERE m_No='$film'";
$ok = mysqli_query($conn,$sql);
$data = mysqli_fetch_array($ok);
$c_r= $data[8];
$c_rc= $data[9];
?>
//displays the movie information and uses radio buttons to get user rating
Then this lets the user rate the movie
<?php
}
function act1()
{
if(isset($_POST['rsub']))
{
global $film;
global $conn;
$rate = $_POST['rate'];
$sqlr= "UPDATE movies SET rating=rating+$rate, rate_count=rate_count+1 WHERE m_No='$film'";
$output = mysqli_query($conn,$sqlr);
}
if($output==1)
{
echo 'Data Stored';
}
else
{
echo 'Data Not Stored ';
echo mysqli_error($conn);
}
}
$conn = null;
?>
</body>
</html>
when only the first function is being used, it works, but when I try to use the rating system, this error comes in the browser, mysqli_query() expects parameter 1 to be mysqli, null given... Any idea on a workaround for this?
Your issue is that the two variables you're relying on with the DB connection, $conn and $film, do not exist when the page has posted back the user rating data.
Your application's lifecycle goes like this:
1) User makes initial request. PHP starts and runs the first code block, it echoes some values to the page, page is returned to the user. Once the page is returned, the request is complete and PHP stops executing. All variables declared and in memory are lost because the process has stopped running.
2) The page returned from the PHP script arrives in the user's browser. User enters their rating and posts the data back to the server. This constitutes an entirely new request.
3) The new request arrives at the server. PHP starts up again. The web is inherently stateless, so by default it remembers nothing of the previous request. Certainly not the names or values in any in-memory variables - the process that contained them died long ago and has no association with the new one.
Therefore, if you have any values that you need to use again in PHP for the second request, you can either create them again, or receive them in the request data, or the first PHP script must have stored them somewhere persistent that you can retrieve them from, such as a session variable or cookie, or database.
It's not clear from your posted code, but presumably in the second request the function act1() gets called somehow and tries to insert the data into the database. It fails because neither $film or $conn have any values in them in this new request.
I suggest you solve it like this:
1) Create your connection object again, this is easy, and you need to re-connect to MySQL for this request anyway.
2) the film you're rating should be passed back from the browser in the form data.
This is the first script, to get the initial film data and render the ratings form to the page.
//re-usable function to connect to DB. Maybe move this out to a separate file so all pages can use it.
function getDBConn() {
return mysqli_connect('localhost','root','','filmsdb');
}
function show()
{
$conn = getDBConn();
$film = $_GET['fm'];
$sql = "SELECT * FROM movies WHERE m_No='$film'";
$ok = mysqli_query($conn,$sql);
$data = mysqli_fetch_array($ok);
$c_r= $data[8];
$c_rc= $data[9];
$conn = null;
}
Your latest update doesn't show the form but I'm going to assume it's something like this, with an additional film hidden field. There should be suitable form tags around it as well.
<input type="radio" value="1" name="rate">
<input type="radio" value="2" name="rate">
<input type="radio" value="3" name="rate">
<input type="radio" value="4" name="rate"><input type="radio" value="5" name="rate">
<input type="hidden" name="film" value="<?php echo $film;?>"/>
<input type="submit" value="Rate" name="rsub">
Now is the second script, to be run when the rating data is submitted. You haven't shown how act1() is called but I'll assume you've got that covered.
function act1()
{
if(isset($_POST['rsub']))
{
$film = $_POST['film']; //get the film ID from the submitted form
$conn = getDBConn(); //assuming this script is in the same .php file as the first block, otherwise you'll need to move getDBConn into a separate php file and then include the file in each script.
$rate = $_POST['rate'];
$sqlr = "UPDATE movies SET rating=rating+$rate, rate_count=rate_count+1 WHERE m_No='$film'";
$output = mysqli_query($conn, $sqlr);
}
if ($output==1)
{
echo 'Data Stored';
}
else
{
echo 'Data Not Stored';
echo mysqli_error($conn);
}
$conn = null;
}
P.S. I know it's just an example project, but if you make a real-life site please heed the comments above re SQL injection, and don't let your applications and websites log into your DB as "root" either - give them only the privileges they actually need.
I'm making a website. and one of the features i want it to have is to have a simple game that connects 2 players together. my problem is I don't know how to make it so both player are in the same "room" because on room holds only 2 players.
On way i approached this is once one player joined, he gets a "wait for next player" message and waits while sending to the database that one player have joined. how do i make it keep checking for the next 3 minutes if the next player joined?
UPDATE
First here is the code so far:
<html>
<title>SiteName (test)</title>
<head>
<?php
$servername = "localhost";
$u
sername =
$password =
$dbname =
try
{
$conn = new PDO("mysql:host=$servername;dbname=$dbname", $username, $password);
// set the PDO error mode to exception
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$stmt = $conn->prepare('SELECT * FROM game');
$stmt->execute(array('gameID' => $gameID));
while($row = $stmt->fetch()) {
print_r($row);
echo "<br />\n";
}
}
catch(PDOException $e)
{
echo $sql . "<br>" . $e->getMessage();
}
?>
<button onclick="myFunction()" id="w">Look for Game</button><br>
<script>
function myFunction() {
var elem = document.getElementById("w").innerHTML = "Wait";
var counter = 10;
var label= document.getElementById("lbl");
var counter = 10;
var clabel= document.createElement("p");
clabel.innerHTML = "You can download the file in 10 seconds.";
var id;
label.parentNode.replaceChild(clabel, label);
id = setInterval(function() {
counter--;
if(counter < 0) {
clabel.parentNode.replaceChild(label, clabel);
clearInterval(id);
} else {
clabel.innerHTML = "You can download the file in " + counter.toString() + " seconds.";
}
}, 1000);
}
</script>
<?php
$conn = null;
?>
</body>
</html>
Am trying to make it so that if the first player joined, he will be waiting (i have it for 10 seconds here as a test) until the other joins. the way am trying to do it is to have a field in the database will know if the a player is in that page and await the next player. I read something about long polling but not sure how to implement it for my case.
Any feed back would be helpful, Thank you
PHP is not the best language to do this in, but if you still want to do it.
Look into using Ratchet (http://socketo.me/), which is a PHP websocket library. A websocket is full duplex, meaning that a connection between the server and client is kept open. Game state and player actions can then be communicated through this.
http://socketo.me/docs/hello-world is an example you can learn from.
first you will want javascript or some client side code to handle this. as php will execute on the server side then display to the user. if you use ajax with javascript you can get the client side and server side to work together.
you will want to use a while loop, in this loop you will set a timeout.
in the while loop you can call the ajax script you want untill you get your result you want. I'm assuming you plan on making this a turn by turn game for the players. you will want a table that sets "true" to if player 1 or player 2 are in the game. if both are turn then the game begins.
Hope this logic helps