Sending data from server to client?
Solution 1
Okay, after many tests and long research i came to the conclusion that PHP server can never interact with a specified client directly unless the client send a request to the server first.
The only reliable solution i found is to use infinite loop which will only break on data change, this will reduce the frequency of ajax requests to the server considerably, hence increasing the performance and decreasing the usage of the Memory and CPU on the client's device, here how it goes:
PHP 1 (Handles data update or new data insert to database):
$process = $_POST['process'];
$log = "/logs/logs.txt";
if($process == 'update'){
//execute mysqli update command and update table.
$str = "Update on " . date('d/m/Y - H:i:s') . "\n";//add some text to the logs file (can be anything just to increase the logs.text size)
file_put_content($log, $str, FILE_APPEND);//FILE_APPEND add string to the end of the file instead or replacing it's content
}
else if($process == 'insert'){
//execute mysqli insert command and add new data to table.
$str = "Added new data on" . date('d/m/Y - H:i:s') . "\n";
file_put_content($log, $str, FILE_APPEND);
}
The above code will insert/update data, create file log.txt
if not existed and add additional text to it on each request. log.txt
will be used later in the infinite loop "below" and would break the loop when it's size change.
PHP 2 (handles reading data requests):
if(isset($_POST['id']) && $_POST['id'] != '' && isset($_POST['size']) && $_POST['size'] != '')
{
$id = (string)$_POST['id'];
$init_size = (int)$_POST['count'];
$size = file_exists('logs/logs.txt') ? (int)filesize('logs/logs.txt') : 0;//$size is logs.txt size or 0 if logs.txt doesn't exist(not created yet).
$select = $con->prepare("SELECT * FROM data WHERE id=?");
$select->bind_param('s', $id);
while(true){ //while(true) will loop indefinitely because condition true is always met
if($init_size !== $size){
$select->execute();
$result = $select->get_result();
while($row = $result->fetch_assoc())
{
$data['rows'][] = array(
"column 1" => $row['column 1'],
"column 2" => $row['column 2'],
);
}
$data['size'] = $size;
echo json_encode($data);
break; //break the loop when condition ($init_size != $size) is met which indicates that database has been updated or new data has been added to it.
}
else{
clearstatcache(); //clears the chached filesize of log.txt
$size = file_exists('logs/logs.txt') ? (int)filesize('logs/logs.txt') : 0;
usleep(100000) //sleep for 100 ms
}
}
}
AJAX:
var size = 0; //declares global variable size and set it's initial value to 0
function send(s){
var formdata = new FormData(),
id = document.getElementById('id').value;
formdata.append('id', id);
formdata.append('size', s);
var xhr = (window.XMLHttpRequest) ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP');
xhr.open('post', 'server.php', true);
xhr.timeout = 25000; //set timeout on xmlhttprequest to 25 sec, some servers has short execution tiemout, in my case it's 27 sec so i set the value to 25 sec.
xhr.send(formdata);
xhr.onreadystatechange = function(){
if(xhr.readyState == 4 && xhr.status == 200){
var data = JSON.parse(xhr.responseText);
size = data.size;
console.log(data.rows);
setTimeout(function(){send(size)}, 100); //re-initiate the request after receiving data
}
}
xhr.ontimeout = function(){
xhr.abort(); //abort the timed out xmlhttp request
setTimeout(function(){send(size)}, 100);
}
send(size);
This is not the ideal solution but it reduced my xmlhttp requests from 2/sec to as low as 1/25 sec, hope that someone will be able to come up with a better solution.
Solution 2
Before we had capabilities to use sockets in browsers, we used Long polling. The basic idea is that instead of the browser making requests at regular intervals, the browser will make a request to the server, but the server won't respond until there is something worthwhile to share back to the browser. That means the request could be left open for 10ms or for hours.
After the server responds with something, it is then the browser's job to make a new ajax request. This way, there is always a line open to the server.
Refer to this question for more information.
Solution 3
You could create an ajax request to an php script which will only return data if there is any new data. As long there is no new data the script keeps running in a loop until there is.
Solution 4
Answering the part of your question about directly editing a session...
To directly manipulate the session of a user, I will assume you know and can track any user's session ID (perhaps in your database on sign in).
When you need to edit a user's session directly on the server:
- Retrieve user's last known session from the database.
- Call
session_close()
to close the current session (if there is one). - Call `session_name($sessionId)' with the session ID.
- Call
session_open()
to open that session.$_SESSION
should be populated with the session data. You will not need to unserialize anything. - Make your edits to the session.
- Call
session_close()
to reserialize the data.
Alternatively, you could directly open the session file, unserialize()
it, edit the data, and re-serialize()
manually.
razz
Updated on August 16, 2020Comments
-
razz almost 4 years
I have a php server file and an HTML client file, the HTML file send ajax requests to the server to retrieve data every
500 ms
, this although works as expected it's causing high usage of memory and CPU on the client's device.PHP
if(isset($_POST['id']) && $_POST['id'] != '' ) { $id = $_POST['id']; $select = $con->prepare("SELECT * FROM data WHERE id=?"); $select->bind_param('s', $id); $select->execute(); $result = $select->get_result(); while($row = $result->fetch_assoc()) { echo $row['column 1'] . "\t" . $row['column 2'] . "\n"; } }
AJAX
function send(){ var formdata = new FormData(), id = document.getElementById('id').value; formdata.append('id', id); var xhr = (window.XMLHttpRequest) ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP'); xhr.open('post', 'server.php', true); xhr.send(formdata); xhr.onreadystatechange = function(){ if(xhr.readyState == 4 && xhr.status == 200){ console.log(xhr.responseText); } } } setInterval(function(){send()}, 500);
I would like to find an alternative solution to ajax, instead of sending numerous requests to the server and retrieving same data most of the time, it would be much more efficient if the server can interact with the client on data change or update.
I can't use PHP
Socket
orHttpRequest
methods as they are not installed on my hosting server and I'm not sure if the later works. The only way I can think of is usingSESSIONS
.According to this PHP server store all users sessions on the same directory on the server, therefore it may be possible to change sessions variables for a particular user directly on the file. The problem however is the data in those files are serialized and I'm not sure how to de-serialize the data and re-serialize them and then save the new data!
Even if I was able to find a way to store updates on the session file, I still need to use setInterval to listen to the session's variable change every
500ms
although it's not ideal but it would be much better than usingXMLHttpRequest
in terms of memory and CPU usage.So what's the best way to do this? any help would be much appreciated.
UPDATE:
I realized that
SESSION
wont work because it can be read only by the server not the client, therefore i have to send ajax request to the server to get the variables which i was trying to avoid.I tried long polling but i had many problems with it,
flush
andob_flush()
doesn't work on my server and i can't change theini
settings. When trying the infinite loop i can't get it to break on data change:if(isset($_GET['size']) && $_GET['size'] != '') { $size = (int)$_GET['size']; $txt = "logs/logs.txt"; $newsize = (int)filesize($txt); while(true) { if($newsize !== $size) { $data = array( "size" => filesize($txt), "content" => file_get_contents($txt)); echo json_encode($data); break; } else{ $newsize = (int)filesize($txt); usleep(400000); } } }
it keeps going on and on, even if the
logs.txt
size increase it won't break! how can I make it break and echo data on size increase?UPDATE 2:
It turned out the php cache the filesize when calling
filesize()
method therefore the above loop will run indefinitely, the solution for that is to useclearstatcache()
method which will clear the stored cache of the file size allowing the loop to break on filesize changes.