Dynamically creating and loading JS - javascript

I am working on a PHP project which writes js files and executes them on page load.
Is it a good practice to write JS file dynamically and append the script tag to the page html and execute it only every page request?
Here is my working creating and linking the JS File:
<?php
if (!function_exists('setScript')) {
function setScript($script = null)
{
static $_script = array();
if ($script == null) {
return $_script;
$_script = array();
} else {
$_script[] = $script;
}
}
}
if (!function_exists('linkJs')) {
function linkJs($controllerName, $actionName)
{
$jsFileName = randomString(40) . '.js';
$folderName = PUBLIC_DIR . DS . 'generated';
if (!is_dir($folderName)) {
mkdir($folderName);
chmod($folderName, 777);
}
$fileName = $folderName . DS . $jsFileName;
$availableFiles = scandir($folderName);
unset($availableFiles[0]);
unset($availableFiles[1]);
foreach ($availableFiles as $file) {
$file = $folderName . DS . $file;
if (is_file($file)) unlink($file);
}
$script = "$(document).ready(function() {\n" . implode("\n", setScript()) . "});";
file_put_contents($fileName, $script);
$url = loadClass('Url', 'helpers');
return "<script type='text/javascript' src='" . $url->baseUrl() . 'public/generated/' . $jsFileName . "'></script>";
}
}
if (!function_exists('alert')) {
function alert($message, $returnScript = false)
{
if (isAjax()) {
if ($returnScript) {
return "\nalert('$message');\n";
}
echo "\nalert('$message');\n";
} else {
setScript("\nalert('$message');\n");
}
}
}
Please suggest if this is a good practice in doing so or any other way i can do it.
Approx 30-40 users would be logged in to the website concurrently and would have approx 5-10 page requests per second. (These are projections. Might go high).
is writing js file (to the hard drive) and linking it is a good practice or just adding the raw scripts to the html body is a good practice since writing to js file gets the js to be un-intrusive.
Also, the javascript generated is going to be dynamic, probably for every page request.

If you can see no other choice than dynamically generating every time (my guess is that the content of the script is at least 80% different for each request) then write the script directly into the html file as linking will cause the browser to make another request to include the script.
You are already going to have degraded performance by dynamically generating the file.
The best way of doing this that I can think of is to actually create a php script that generates the js by itself and then create a .htaccess rewrite rule to rewrite /script/generator/{HASH_FOR_REQUEST}.js to /path/to/php-script-generator.php so that you can leverage browser caching if the request is the same.
However, if it is only specific details about the JS that change and the js functions body remains pretty similar (ie, you are using the js to report info back to the client) then consider writing the js in a php file and then using php inline tags to echo the stuff you need to change.
For example:
This script will write an alert to the js so then when loaded with a query string it will report back what is in the query...
<?php
// disable output buffering
/* the reason for this is that the browser will wait
* for the first byte returned before continuing with the page.
* If it has to wait for the whole file performance will be degarded.
*/
while(ob_get_level() != 0) ob_end_clean();
header("Content-type:text/javascript");
// it is wise to set some cache headers here
if(isset($_GET['message']) {
$message = urldecode($_GET['message']);
} else {
$message = "No message!";
}
?>
// write the js...
alert("<?php echo $message; ?>");
By requesting /path/to/script.php?message=hello+world the script will return alert("hello world");

Related

How to refresh the web page when index changes without lagging the server

I would like to refresh my static web page running on apache when the index changes. I've already tried to use server-side events, where I had a PHP file checking if the index changed and if yes, it sent the event to the webpage. This works exactly how I want, but there is a problem. Because the page is used by a lot of people sometimes (tens or up to a hundred opened tabs), it quickly starts to spam many apache processes. Then, it reaches the limit, and the apache freezes.
The question is how to handle this. If a user closes the tab, the process is killed, however, if not, the apache freezes.
The PHP script looks like this (it is checking two things, first, if the file chenged, or second if the status is something. As I said, this works fine, the problem is its lagging the server):
<?php
session_start();
session_write_close();
ignore_user_abort(false);
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
$filename = "index.html";
while(True){
if ( connection_aborted() ){
exit();
}else{
try{
$string = file_get_contents("current_status.json");
$json = json_decode($string, true);
$pom1 = $json["state"];
$t1 = shell_exec("date -r index.html");
sleep(3);
$pom2 = $json["state"];
if($t1 != shell_exec("date -r index.html")) {
sleep(2);
echo "data: file changed \n\n";
} else if($pom2=="ready") {
sleep(2);
echo "data: new shot available \n\n";
} else {
echo "heartbeat";
}
ob_flush();
flush();
}
catch (\Error $e){
echo "data: error, json not available \n\n";
}
}
}
ob_end_flush()
?>
Then, there is a classical javascript function in the index file with event source on the PHP file.
My question is, how can I do this to not make apache crashing? Can I somehow set up SSE to handle it? I know I can allow more processes on apache, but my resources are limited.
Is there any other way how to do this? For example, live.js works as well, but the problem is the sam, a lot of processes when opened multiple times.
Yes, I can see how this would put far more strain on your server than necessary.
What you should do is poll for changes from javascript. You send an asynchronous request for the last time the index file changed from your javascript. You do it once when the page loads and store the time. Then you check again on an interval and compare the result with the first one. If it changed you refresh the page.
The PHP script should get the last change date, output it and exit - no continuously running PHP scripts.
Here is what the PHP file should look like:
<?php
header('Content-type: text/plain');
echo filemtime('index.html');
?>
Keep this minimal. The built in filemtime function is more efficient than running shell_exec commands.
Here is an example javascript:
chk_index_change_time(false);
function chk_index_change_time(last){
fetch('http://yourdomain.com/yourpath/get_index_change_time.php')
.then(res => res.text())
.then((index_change_time) => {
if ((false !== last) && (last != index_change_time)){
location.reload();
} else {
setTimeout(chk_index_change_time, 3000, index_change_time);
}
});
}
Feel free to error handling or whatever, but this will work. I used a timeout here instead of interval so that if the server is slow the server response time doesn't come out of the 3 second delay.

How can i open, read, close, update, reopen and read a file without refreshing in php

I am trying to make a chat application using html and php.
I am writing a .txt file with the whole chat in it and want to read it every five seconds without refreshing my page. I tried to use a loop in javascript, but it dont refreshes the file after open it again.
function readChat(){
clearArea();
<?php
if ($file = fopen("chat.txt", "r")) {
while(!feof($file)) {
$line = trim(fgets($file));
if($line !== " "){
$arr = explode(":", $line, 2);
$name = $arr[0];
$string = $arr[1];
$string = str_replace(array("\r", "\n"), '', $string);
if($name === $_COOKIE["username"] && $string !== "" && $string !== " " && $string !== "\n"){
echo "selfMessage(\"".$string."\");";
}else if($line !== "" && $line !== " " && $line !== "\n" && $string !== "" && $string !== " " && $string !== "\n"){
echo "otherMessage(\"".$string."\", \"".$name."\");";
}
}
}
fclose($file);
}
?>
}
window.setInterval(function() {
readChat();
}, 5000);
This is what i tried so far.
The problem you are having is due to mixing PHP and Javascript code.
First you should know that the PHP code executes on the server which generates the page content that will be sent to the client (web browser). Then that web browser executes the Javascript code contained in the page content it receives.
Can you see already why the chat isn't updating?
Your PHP function executes just once, when the page is requested, and inserts the chat messages into the body of the readChat() function. When the browser receives the web page data that contains readChat() it just sees the chat messages as if they were hard-coded into the function!
For Example, the following PHP script:
function someJSFunc() {
<?php
$now = date('m/d/Y H:i:s', time());
echo "var now = '$now';";
?>
console.log(now);
}
Results in the following function being sent to the client:
function someJSFunc() {
var now = '6/4/2019 16:39:18';
console.log(now);
}
No matter how many times the client calls someJSFunc() it will always output the same date and time because that was the time that the PHP function executed.
Sometimes mixing PHP and Javascript this way can be very useful, but to accomplish what you are looking for you are going to need to use AJAX requests.
An AJAX request can be accomplished easily using JQuery. All you need to do is add another <script> tag to your page header to include the JQuery script. Further instructions on setting up JQuery can be found on their website.
Next you have to fix your readChat() function. Instead of using PHP in that function, just use javascript and use JQuery to perform a GET request.
function readChat() {
clearArea();
$.get("getchat.php", function(data) {
// inside this function data will contain whatever your PHP script echos
$('#chat').html(data); // for example, replacing a div with id="chat" with the data received from getchat.php
});
window.setInterval(function() { readChat(); }, 5000); // I would personally move this outside of readChat() so that it is only called once...
}
This function will load getchat.php every time the browser calls readChat(), and set up an interval to call readChat() every 5 seconds. The function inside $.get() is where you can use the data received from getchat.php. It is usually just a string that you can insert into your chat area or div, but it depends on how you make the getchat.php script work.
Lastly you just make a new PHP script called getchat.php that will read the chat file and echo it in the format that you would like to see added to the page.

Is there a way to create and modify HTML and Javascript files dynamically?

I have a project whose requirements have been consistently expanding. At first, it was fine because I could hard code most of it. However, I find that I am making different versions of the same type of forms and programming specific JS files to go along with them. Is there a way to dynamically create an HTML and JS file? So, maybe I could write a function or something that reads requirements from a text files, and from that, build an HTML file, a JavaScript file, and modify other JavaScript files within the directory. For example:
Say I have a JS file named main.js
/* I hold all the basic requirements and functions for every form*/
var blueForm = ...
var redForm = ...
There currently exists HTML files named blueForm.html and redForm.html.
I want to add a function to main.js such that:
function createNewForm(requirements){
. . .
createHTML();
createJS();
modifyMain(this); /* as in this file (main.js) */
. . .
if(successful){ return 0; }
return 1;
}
Now main.js should have been modified like:
var blueForm = ...
var redForm = ...
var greenForm = ...
And now there exists HTML files named blueForm.html, redForm.html, and greenForm.html.
The answer is yes. The most accessible way of doing this is using php, most commonly implemented through a Linux / Apache / MySQL / PHP stack (LAMP). HTML and JS be easily injected into a file your browser reads as html.
Here's a sample.php file:
<html>
<body>
<?php
echo "Hello World";
echo "<script>";
$myvar = 1;
if ($myvar==1) {
echo "function dosomethingjavascripty() {";
echo "console.log('doing it');";
echo "}";
}
echo "</script>";
?>
</html>
</body>

Can't populate <div> with elements of a json_encoded php array

This function worked previously (the last time I opened this project over a week ago), but now I can't seem to get it to work at all and I have no idea how to figure out what's going wrong! First, I'll diagram my file architecture in case my file paths are incorrect and causing my php to not even be called:
~/Sites
proj1
htdocs
index.html
ajax.php
scripts
java_script.js
styles
style_sheet.css
includes
scrapedImages
.
.
.
Here's the JS function that uses AJAX to call a .php script:
function requestServer() {
$.getJSON('/Users/aweeeezy/Sites/proj1/htdocs/ajax.php', function(data) {
$.each(data, function(key, val) {
var html = "<img src='/Users/aweeeezy/Sites/proj1/includes/scrapedImages/"+val+"' style='display:block;max-width:20px;max-height:20px;width:auto;height:auto' alt=null />"
$('#puppy-box').prepend(html);
});
});
}
The line setting var html was <img src='...'+images[i]+"... when I first opened the project this morning, but I'm not sure why...I think because I was testing the site out, it was faster to only load a fraction of the images and used a for loop to cycle through only the first 10 or so pictures, hence the i index. Anyway, shouldn't it be data[i], or val[i]...or data[val]? I have no idea what's going on here.
Here's the ajax.php file that the JS function is trying to call:
<?php
$images = scandir('/Users/aweeeezy/Sites/proj1/includes/scrapedImages/');
/*foreach ($images as $key => $image) {
if ($image == '.' || $image == '..') {
unset($images[$key]);
}
}*/
echo json_encode($images);
?>
I commented out the middle part because I wasn't sure if this was causing a complication. I tried putting both echo and print lines in here to see if the script is being called, but even if they are working, I can't really see them because they're being returned as data (I think) to the JS function that calls the script.
How do I even go about debugging this mess and get my girlfriend's valentine's day project back on track!

Workflow with (non-) minified js/css files for development and production

I'm looking for a way to structure my workflow so I don't get confused/into trouble when working with "uncompressed" js/css files for development and minified ones for production.
I don't want to have two html versions (one with development and one with minified js/css files) of the same source. Or do I have to?
Also whats the best way to automate the actual minify process?
NOTE: I'm looking for a local solution. Server side is not an option.
I've been using this in PHP – you might use it for inspiration:
<?
$test_server = $_SERVER['SERVER_NAME'] == "127.0.0.1" || $_SERVER['SERVER_NAME'] == "localhost" || substr($_SERVER['SERVER_NAME'],0,3) == "192";
function caching_headers ($timestamp) {
global $test_server;
if (!$test_server) {
$gmt_mtime = gmdate('r', $timestamp);
if(isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])) {
if ($_SERVER['HTTP_IF_MODIFIED_SINCE'] == $gmt_mtime) {
header('HTTP/1.1 304 Not Modified');
exit();
}
}
header('Last-Modified: '.$gmt_mtime);
}
}
header ("Content-Type: application/javascript; charset=utf-8");
include ($_SERVER['DOCUMENT_ROOT']."/media/js/jsmin.php");
$libs = explode("|",$_GET['libs']);
$uniq_string = "";
foreach ($libs as $lib) {
$uniq_string .= filemtime($_SERVER['DOCUMENT_ROOT']."/media/js/$lib.js");
}
$hash = md5($uniq_string);
$cachefile = $_SERVER['DOCUMENT_ROOT']."/cache/".$hash.".js";
if(file_exists($cachefile)) {
$last_mod = filemtime($cachefile);
caching_headers ($last_mod);
include($cachefile);
echo "//Cached on ".gmdate('r', $last_mod)." to ".$hash;
exit;
} else {
$combined = "";
foreach ($libs as $lib) {
if (substr($lib, strlen($lib)-3, 3) == "min") {
$combined .= file_get_contents($_SERVER['DOCUMENT_ROOT']."/media/js/$lib.js")."\n";
} else {
$combined .= JSMin::minify(file_get_contents($_SERVER['DOCUMENT_ROOT']."/media/js/$lib.js"))."\n";
}
}
$fp = fopen($cachefile, 'w');
fwrite($fp, $combined);
fclose($fp);
$last_mod = filemtime($cachefile);
caching_headers ($last_mod);
include($cachefile);
echo "//Cached on ".gmdate('r', $last_mod)." to ".$hash;
}
?>
alongside JSMin-php.
I then use:
<script src="/media/js/combined.php?libs=jquery-1.5.1.min|behaviour|jquery.form"></script>
in my pages.
It stores the cached minified file at /cache/, so make sure that folder exists if you are trying this.
Currently the best solution is the HTML5 boilerplate build script.
Beware that there is a learning curve before being able to use the complete power.
Also it's worth mentioning, that the build script optimized for websites, where every page uses the same JavaScript and CSS files. So if you have certain pages, that have additional CSS and JavaScript files that you want to have optimized/minified you might need to do this separately.
The script also compresses HTML and (optionally) leaves PHP stuff untouched.
HTML5 boilerplate build script is awesome. It's open source, please contribute!
Note: Most of my infos are 3+ month old. Let me know about new developments.
You could dynamically inject the appropriate js include depending on the URL. In essence, you check to see if it's the production URL, and if it is include the minified version. Then use an else branch to handle non-production URLs and inject the development version (this way someone can't see your staging URL).

Categories