Re-execute a PHP script in a JavaScript function - javascript

I wrote a code to re-read a content of a file (on the server) every time the file is modified. The scenario is like this:
- The webpage is loaded
- If the file (on the server) is newer than the starting time of the page (the time when the webpage was started), the content of the file is read
- If the file is modified later, the content must be read again by PHP script
I tried this using EventSource. Here is the code for the browser:
<html>
<head>
<?php
$startTime = time();
$flag = 0;
?>
<script type="text/javascript" language="javascript">
lastFileTime = <?php echo $startTime; ?>;
var fileTime;
if(typeof(EventSource) !== "undefined") {
var source=new EventSource("getFileTime.php");
source.onmessage = function(event) {
fileTime = parseInt(event.data);
if (fileTime > lastFileTime) {
readFile();
lastFileTime = fileTime;
}
};
}
else {
alert("Sorry, your browser does not support server-sent events.");
}
function readFile() {
<?php
$fid = fopen("file.bin", "rb");
... // Read the content of the file
$flag = $flag + 1;
?>
... // Transfer the content of the file to JavaScript variables
flag = <?php echo $flag; ?>;
}
</script>
</head>
<body>
...
</body>
</html>
And here is the server-side code (getFileTime.php):
<?php
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
$filetime = filemtime("file.bin");
echo "data: {$filetime}\n\n";
flush();
?>
When I start the webpage and created file.bin afterwards, readFile() is called for the first time (I checked the value flag = 1. But then, if I modified file.bin again, obviously readFile() is not called. I checked the content of the file; it's still from the previous file, and also flag is still 1. It seems that a PHP script in a JavaScript function can only be called once. How to re-execute the PHP script in a JavaScript function?

Your PHP script needs to remain active, sending new events to the client when something changes:
<?php
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
$lastFiletime = null;
while (true) {
$filetime = filemtime("file.bin");
if ($filetime != $lastFiletime) {
echo "data: {$filetime}\n\n";
$lastFiletime = $filetime;
flush();
}
}

Related

Server Side Events, HTML5, PHP & Javascript... index page not 'refreshing'

I found a really good article with a feature I want to add to a page, but have been stuck the entire day with one small error. For reference the tutorial is located here.
Everything is working, the only thing that is not happening is the fact that the index.php webpage is not refreshing on changes made to the hosted php array. Could anyone glance at my code and tell me if I have a typo or missed part of the article?
My array file - selectedSystemStateResults.php
<?php
$selectedSystemStateResults = ["cart", "dogsss", "cows", "zebra", "snake"];
My serverside PHP script file - selectedSystemState-script.php
<?php
header("Cache-Control: no-cache");
header("Content-Type: text/event-stream");
// Require the file which contains the $animals array
require_once "selectedSystemStateResults.php";
// Encode the php array in json format to include it in the response
$selectedSystemStateResults = json_encode($selectedSystemStateResults);
echo "data: $selectedSystemStateResults" . "\n\n";
flush();
echo "retry: 1000\n";
echo "event: selectedSystemStateResultsMessage\n";
My Client side web page - index.php
<?php require "selectedSystemStateResults.php"; ?>
<html>
<body>
<?php foreach ($selectedSystemStateResults as $selectedSystemStateResult) : ?>
<li><?php echo $selectedSystemStateResult; ?></li>
<?php endforeach ?>
</ul>
<script src="/selectedSystemState-script.js"></script>
</body>
</html>
My javascript file - selectedSystemState-script.js
let eventSource = new EventSource('selectedSystemState-script.php');
eventSource.addEventListener("selectedSystemStateResultsMessage", function(event) {
let data = JSON.parse(event.data);
let listElements = document.getElementsByTagName("li");
for (let i = 0; i < listElements.length; i++) {
let selectedSystemStateResults = listElements[i].textContent;
if (!data.includes(selectedSystemStateResults)) {
listElements[i].style.color = "red";
}
}
});
I have read this and re-read this for the past 8 hours and feel really stuck. Does anyone see any blaring php or javascript typos or could the tutorial be wrong?
Please pardon the typo I had in the file names on my unedited original post. The directory shows the files all named properly.
Using this tutorial Using server-sent events
I found out that the script.php file must NOT stop executing !!
or (selectedSystemState-script.php) in your case .
So I guess the the tutorial you linked is wrong in some point ?
try this
while (1) {
// Every second, send a "selectedSystemStateResultsMessage" event.
echo "event: selectedSystemStateResultsMessage\n";
require("selectedSystemStateResults.php");
$selectedSystemStateResults = json_encode($selectedSystemStateResults);
echo "data: $selectedSystemStateResults" . "\n\n";
ob_end_flush();
flush();
sleep(1);
}
this is new to me but i noticed a few things :
1- the php event script file must have header text/event-stream
2- that file must not stop executing !
3- event: is sent before data: .
Hope this help
EDIT
After a test on your script It worked when I changed
<script src="/selectedSystemState-script.js"></script>
to <script src="./selectedSystemState-script.js"></script>
it was calling selectedSystemState-script.js from root folder ! and generate 404 error
and in selectedSystemState-script.php
<?php
header("Cache-Control: no-cache");
header("Content-Type: text/event-stream");
// Require the file which contains the $animals array
require_once "selectedSystemStateResults.php";
// Encode the php array in json format to include it in the response
$selectedSystemStateResults = json_encode($selectedSystemStateResults);
// data after event
flush();
echo "retry: 1000\n";
echo "event: selectedSystemStateResultsMessage\n";
echo "data: $selectedSystemStateResults" . "\n\n";
?>
and I edited selectedSystemState-script.js a bit :
let eventSource = new EventSource('selectedSystemState-script.php');
eventSource.addEventListener("selectedSystemStateResultsMessage", function(event) {
let data = JSON.parse(event.data);
let listElements = document.getElementsByTagName("li");
for (let i = 0; i < listElements.length; i++) {
let selectedSystemStateResults = listElements[i].textContent;
if (!data.includes(selectedSystemStateResults)) {
listElements[i].style.color = "red";
} else {
listElements[i].style.color = "blue";
}
}
});
<script src="/selectedSystemState-script.js"></script>
does not match your javascript filename selectSystemState-script.js. Verify javascript errors next time by opening the developer tools console!
Another error is that you're sending the data before setting the event name. The end of selectedSystemState-script.php should be:
echo "retry: 1000\n";
echo "event: selectedSystemStateResultsMessage\n";
echo "data: $selectedSystemStateResults" . "\n\n";
flush();

PHP session variable and javascript variable are asynchronous

I have a captcha generator php script:
<?php
session_start();
header ("Content-type: image/png");
/*irrelevant parts here*/
$word = "";
for ($i = 0; $i < 4; $i++) {
$letter = $letters[rand(0, $len - 1)];
imagettftext($image, 15, 0, $i*50+25, 50, $text_color, $font, $letter);
$word .= $letter;
}
$_SESSION['captcha_string'] = $word;
imagepng($image);
?>
I call it this way in my HTML/PHP page:
<?php session_start(); ?>
<!DOCTYPE html>
.. some irrelevant code here ..
<img id="captchaimg" src="captcha_generator.php">
And this is my javascript code which is on the same HTML/PHP page (I call this function with a button click):
<script type="text/javascript">
function validCaptcha() {
var a = <?php echo json_encode($_SESSION['captcha_string']); ?>;
alert(a);
}
</script>
My problem is that the javascript "is late", it gets the previous value of the session variable, not the actual. I think the reason is that when the page is loading the php runs AFTER the javascript did get the session variable. So, the javascript sees the previous session variable, while there is already a new one.
How can I get the ACTUAL session variable in the javascript function?
UPDATE to the question: when does the javascript function get the session variable? When the page is loading or when the user clicks the button?
1.Here problem is the while loading page only variable a= sessionvalue assigned with session value.
2.Here you are creating captcha code after loading page and reassigning session value.
3.In php session value get updated.But in JS doesn't.
one alternative solution is send ajax call when you click on button and return session($_SESSION['captcha_string']) value from PHP. This could resolve your problem.
OK, I found the solution. The key >> I had to make a new php file (called captchavalue.php in the example) which only has one task: echo the variable:
<?php
session_start();
echo $_SESSION['captcha_string'];
?>
And here is the Ajax/Javascript (thanks for suggestion):
<script>
function validCaptcha() {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
document.getElementById("div_id").innerHTML = this.responseText;
}
};
xhttp.open("GET", "includes/captchavalue.php", true);
xhttp.send();
}
</script>

Add JavaScript function to wordpress theme

A plugin developer who developed a comments-plugin that I use has instructed me to add the following JavaScript:
function WPACLoadMoreComments() {
window.WPACLoadMoreCount = window.WPACLoadMoreCount || 1;
var url = (new Uri(location.href)).replaceQueryParam('WPACTake', window.WPACLoadMoreCount * 20).toString();
if (WPAC.LoadComments(url, {updateUrl: false})) {
window.WPACLoadMoreCount++;
}
}
I assume he meant to put it in functions.php but the site doesn't load when I insert this code. I tried to inset it at the end, I tried to wrap it with
<?php
the function...
?>
How do I do that correctly?
You need to add the code to a javascript file and enqueue it in functions.php, or echo it via an action hook.
There's a section about including JavaScript right in the codex that's worth a read.
add below code into your functions.php file
function comment_script(){
$html = "<script type='text/javascript'>
function WPACLoadMoreComments() {
window.WPACLoadMoreCount = window.WPACLoadMoreCount || 1;
var url = (new Uri(location.href)).replaceQueryParam('WPACTake', window.WPACLoadMoreCount * 20).toString();
if (WPAC.LoadComments(url, {updateUrl: false})) {
window.WPACLoadMoreCount++;
}
}
</script>";
echo $html;
}
add_action('wp_footer','comment_script');
This is a Javascript function, not a PHP function. This means that you need to do the following:
<?php
// Your existing PHP code here
?>
<script>
function WPACLoadMoreComments() {
window.WPACLoadMoreCount = window.WPACLoadMoreCount || 1;
var url = (new Uri(location.href)).replaceQueryParam('WPACTake', window.WPACLoadMoreCount * 20).toString();
if (WPAC.LoadComments(url, {updateUrl: false})) {
window.WPACLoadMoreCount++;
}
}
</script>
<?php
//Your remaining PHP code
?>
Another possibility is to do it this way:
<?php
echo "<script>";
echo " function WPACLoadMoreComments() {";
echo " window.WPACLoadMoreCount = window.WPACLoadMoreCount || 1;";
echo "var url = (new Uri(location.href)).replaceQueryParam('WPACTake', window.WPACLoadMoreCount * 20).toString();"
echo " if (WPAC.LoadComments(url, {updateUrl: false})) {";
echo " window.WPACLoadMoreCount++;";
echo " }";
echo "}";
echo "</script>";
?>
The reason we're doing it this way is that Javascript is not executed on the server but on the user's browser (client side). Thus, there is no need to put the Javascript in <?php ?> tags, because you do not want it to be executed as PHP code. Since it will be executed by the browser, this means you need this code to appear in the HTML document loaded by the browser, and hence you should use echo or write it within <script> tags outside the <?php ?>
Performance-wise, it is always better to put Javascript code at the end of your page. This is to make sure that any possible lags, caused by the JS code while a user's browser is loading your page, do not affect the rendering of the page.
Put it in the functions.php or footer.php file somewhere outside <?php ?> and wrap it into <script type="text/javascript">Your function here...</script>

Trouble with php variables and ajax javascript

ok I have edited this to another couple of questions I've asked on a similar issue, but I really am in a rush so thought I'd start a new one, sorry if it bothers anyone.
first I have a php script on test.php on the apache server
<?php
//create connection
$con = mysqli_connect("localhost", "user", "password", "dbname");
//check connection
if (mysqli_connect_errno()){
echo "failed to connect to MySQL: " . mysqli_connect_error();
}
$grab = mysqli_query($con, "SELECT * FROM table");
$row = mysqli_fetch_array($grab);
$name = $row["name"];
$color = $row["color"];
$price = $row["price"];
$n1 = $name[0];
$c1 = $color[0];
$p1 = $price[0];
?>
Then I've got this ajax script set to fire onload of page a webpage written in html. so the load() function is onload of the page in the body tag. This script is in the head.
function load(){
var xmlhttp = new XMLHttpRequest();
xmlhttp.open("GET", "test.php", true);
xmlhttp.send();
xmlhttp.onreadystatecahnge = function(){
if(xmlhttp.readyState == 4 && xmlhttp.status == 200){
document.getElementById("itemNameLink1").innerHTML = "<?php echo $n1;?>;
}
}
}
ok so what I want is the $n1 variable in the php script to be used in the javascript ajax code. Where the script is, but I'm not sure where or how to make use of the variable, I've tried a few things. All that happens right now is the innerHTML of itemNameLink1 just disappears.
I'm quite new so any advise would be appreciated, thanks.
The response (this is what you echo in php) returned from request you can get by responseText attribute of XMLHttpRequest object.
So first your JS code should be:
function load(){
var xmlhttp = new XMLHttpRequest();
xmlhttp.open("GET", "test.php", true);
xmlhttp.send();
xmlhttp.onreadystatecahnge = function(){
if(xmlhttp.readyState == 4 && xmlhttp.status == 200){
document.getElementById("itemNameLink1").innerHTML = xmlhttp.responseText;
}
}
}
now in php echo $n1 variable:
....
$grab = mysqli_query($con, "SELECT * FROM table");
$row = mysqli_fetch_array($grab);
$name = $row["name"];
$color = $row["color"];
$price = $row["price"];
$n1 = $name[0];
$c1 = $color[0];
$p1 = $price[0];
// echo it to be returned to the request
echo $n1;
Update to use JSON for multiple variables
so if we do this:
$name = $row["name"];
$color = $row["color"];
$price = $row["price"];
$response = array
(
'name' => $name,
'color' => $color,
'price' => $price
);
echo json_encode($response);
Then in javascript we can parse it again to have data object containing 3 variables.
var data = JSON.parse(xmlhttp.responseText);
//for debugging you can log it to console to see the result
console.log(data);
document.getElementById("itemNameLink1").innerHTML = data.name; // or xmlhttp.responseText to see the response as text
Fetching all the rows:
$row = mysqli_fetch_array($grab); // this will fetch the data only once
you need to cycle through the result-set got from database: also better for performance to use assoc instead of array
$names = $color = $price = array();
while($row = mysqli_fetch_assoc($grab))
{
$names[] = $row['name'];
$color[] = $row['color'];
$price[] = $row['price'];
}
$response = array
(
'names' => $names,
'color' => $color,
'price' => $price
);
You can dynamically generate a javascript document with php that contains server side variables declared as javascript variables, and then link this in the head of your document, and then include this into your document head whenever server side variables are needed. This will also allow you to dynamically update the variable values upon page generation, so for example if you had a nonce or something that needs to change on each page load, the correct value can be passed upon each page load. to do this, you need to do a few things. First, create a php script and declare the correct headers for it to be interpreted as a script:
jsVars.php:
<?php
//declare javascript doc type
header("Content-type: text/javascript; charset=utf-8");
//tell the request not to cache this file so updated variables will not be incorrect if they change
header('Cache-Control: no-cache, no-store, must-revalidate'); // HTTP 1.1.
header('Pragma: no-cache'); // HTTP 1.0.
header('Expires: 0'); // Proxies.
//create the javascript object
?>
var account = {
email: <?= $n1; ?>,
//if you need other account information, you can also add those into the object here
username: <?= /*some username variable here for example */ ?>
}
You can repeat this for any other information you need to pass to javascript on page load, and then reference your data using the namespaced javascript object (using object namespacing will prevent collisions with other script variables that may not have been anticipated.) wherever it is needed as follows:
<script type="text/javascript>
//put this wherever you need to reference the email in your javascript, or reference it directly with account.email
var email = account.email;
</script>
You can also put a conditional statement into the head of your document so it will only load on pages where it is needed (or if any permission checks or other criteria pass as well). If you load this before your other scripting files, it will be available in all of them, provided you are using it in a higher scope than your request.
<head>
<?php
//set the $require_user_info to true before page render when you require this info in your javascript so it only loads on pages where it is needed.
if($require_user_info == TRUE): ?>
<script type="text/javascript" href="http://example.com/path-to-your-script/jsVars.php" />
<?php endif; ?>
<script type="text/javascript" href="your-other-script-files-that-normally-load" />
</head>
You can also do this for any other scripts that have to load under specific criteria from the server.
You should define the PHP variable. And use that variable in your javascript:
<?php
$n1 = "asd";
?>
<html>
<head></head>
<body>
<div id="itemNameLink1"></div>
<script>
function load()
{
var xmlhttp = new XMLHttpRequest();
xmlhttp.open('GET', '/test.php', true);
xmlhttp.send(null);
//Note you used `onreadystatecahnge` instead of `onreadystatechange`
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
document.getElementById("itemNameLink1").innerHTML = '<?=$n1?>';
}
}
}
load();
</script>
</body>
</html>

PHP: Running Multiple Scripts at the Same Time for the Same Client

I have one PHP script that can take several minutes to complete. The script downloads a file to the user PC.
I have another PHP script and its role is to monitor progress of the main download script. That script is called by the client via AJAX calls and should return download progress information.
Right now, my tests show, that during the execution of the main script(in other words, during file download), the AJAX - monitor script returns no values at all. It starts behaving normally, when the main - Download script finishes.
Is it possible that PHP can not run two or more scripts simultaneously and it allows to run script only in sequential order?
I could insert my code, but I think for the purpose of my question, it is not needed. I simply need to know, if two or more PHP scripts may run simultaneously for the same client.
I use:
WAMP
PHP Version 5.4.12
JavaScript without jQuery
Code Used:
As I was asked to show you my code, please, see the below code parts.
Main PHP(later Download) Script:
<?php
// disable script expiry
set_time_limit(0);
// start session if session is not already started
if (session_status() !== PHP_SESSION_ACTIVE)
{
session_start();
}
// prepare session variable
$_SESSION['DownloadProgress'] = 0;
for( $count = 0; $count < 60; $count++)
{
sleep(1);
echo "Iteration No: " . $count;
$_SESSION['DownloadProgress']++;
echo '$_SESSION[\'DownloadProgress\'] = ' . $_SESSION['DownloadProgress'];
flush();
ob_flush();
}
?>
Monitoring PHP script:
// construct JSON
$array = array("result" => 1, "download_progress" => $_SESSION['DownloadProgress']);
echo json_encode($array);
?>
JavaScript code, where I call the both PHP scripts:
SearchResults.myDownloadFunction = function()
{
console.log( "Calling: PHP/fileDownload.php" );
window.location.href = 'PHP/fileDownload.php?upload_id=1';
console.log( "Calling: getUploadStatus()" );
FileResort.SearchResults.getUploadStatus();
console.log( "Called both functions" );
};
JavaScript AJAX:
// call AJAX function to get upload status from the server
SearchResults.getUploadStatus = function ()
{
var SearchResultsXMLHttpRequest = FileResort.Utils.createRequest();
if (SearchResultsXMLHttpRequest == null)
{
console.log("unable to create request object.");
}
else
{
SearchResultsXMLHttpRequest.onreadystatechange = function ()
{
console.log("Response Text: " + SearchResultsXMLHttpRequest.responseText);
console.log("AJAX Call Returned");
if ((SearchResultsXMLHttpRequest.readyState == 4) && (SearchResultsXMLHttpRequest.status == 200))
{
//if (that.responseJSON.result == "true")
{
var responseJSON = eval('(' + SearchResultsXMLHttpRequest.responseText + ')');
console.log("Download Progress: " + responseJSON.download_progress);
}
}
}
var url = "PHP/fileDownloadStatus.php";
SearchResultsXMLHttpRequest.open("POST", url, true);
SearchResultsXMLHttpRequest.send();
}
};
Code Update I:
PHP Script that will later download files:
<?php
// disable script expiry
set_time_limit(0);
for( $count = 0; $count < 60; $count++)
{
sleep(1);
}
?>
PHP Monitoring script that outputs test values:
<?php
$test_value = 25;
// construct JSON
$array = array("result" => 1, "download_progress" => $test_value);
//session_write_close();
echo json_encode($array);
?>
Both scripts are called followingly:
SearchResults.myDownloadFunction = function()
{
console.log( "Calling: PHP/fileDownload.php" );
window.setTimeout(FileResort.SearchResults.fileDownload(), 3000);
console.log( "Calling: getUploadStatus()" );
window.setInterval(function(){FileResort.SearchResults.getDownloadStatus()}, 1000);
console.log( "Called both functions" );
};
Without more info there are a few possibilities here, but I suspect that the issue is your session. When a script that uses the session file start, PHP will lock the session file until session_write_close() is called or the script completes. While the session is locked any other files that access the session will be unable to do anything until the first script is done and writes/closes the session file (so the ajax calls have to wait until the session file is released). Try writing the session as soon as you've done validation, etc on the first script and subsequent scripts should be able to start.
Here's a quick and dirty approach:
The "Landing" page:
This is the page that the user is going to click the download link
<html>
<head>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script>
$(document).ready(function(e) {
//Every 500ms check monitoring script to see what the progress is
$('#large_file_link').click(function(){
window.p_progress_checker = setInterval( function(){
$.get( "monitor.php", function( data ) {
$( ".download_status" ).html( data +'% complete' );
//we it's done or aborted we stop the interval
if (parseInt(data) >= 100 || data=='ABORTED'){
clearInterval(window.p_progress_checker);
}
//if it's aborted we display that
if (data=='ABORTED'){
$( ".download_status" ).html( data );
$( ".download_status" ).css('color','red').css('font-weight','bold');
}
})
}, 500);
});
});
</script>
</head>
<body>
<div class="download_status"><!-- GETS POPULATED BY AJAX CALL --></div>
<p>Start downloading large file</p>
</body>
</html>
The "File Uploader"
This is the PHP script that serves the large file... it breaks it into chunks and after sending each chunk it closes the session so the session becomes available to other scripts. Also notice that I've added a ignore_user_abort/connection_aborted handler so that it can take a special action should the connection be terminated. This is the section that actually deals with the session_write_close() issue, so focus on this script.
<?php
/*Ignore user abort so we can catch it with connection_aborted*/
ignore_user_abort(true);
function send_file_to_user($filename) {
//Set the appropriate headers:
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename='.basename($filename));
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($filename));
$chunksize = 10*(1024); // how many bytes per chunk (i.e. 10K per chunk)
$buffer = '';
$already_transferred =0;
$file_size = filesize( $filename );
$handle = fopen($filename, 'rb');
if ($handle === false) {
return false;
}
while (!feof($handle)) {
/*if we're using a session variable to commnicate just open the session
when sending a chunk and then close the session again so that other
scripts which have request the session are able to access it*/
session_start();
//see if the user has aborted the connection, if so, set the status
if (connection_aborted()) {
$_SESSION['file_progress'] = "ABORTED";
return;
}
//otherwise send the next packet...
$buffer = fread($handle, $chunksize);
echo $buffer;
ob_flush();
flush();
//now update the session variable with our progress
$already_transferred += strlen($buffer);
$percent_complete = round( ($already_transferred / $file_size) * 100);
$_SESSION['file_progress'] = $percent_complete;
/*now close the session again so any scripts which need the session
can use it before the next chunk is sent*/
session_write_close();
}
$status = fclose($handle);
return $status;
}
send_file_to_user( 'large_example_file.pdf');
?>
The "File Monitor"
This is a script that is called via Ajax and is in charge of reporting progress back to the Landing Page.
<?
session_start();
echo $_SESSION['file_progress'];
?>

Categories