I'm trying to create a cron file in PHP. The application I've created has around 30 active users. I want each user to run a JavaScript web-worker periodically in the background which invokes a PHP file (via ajax/xmlhttprequest) that calls a PHP file to run.
Do JavaScript Web-Workers, when calling a PHP file via the Worker, block the main PHP requests from being executed, since they come from the same browser?
To do that you'll need to put an state to close the execution while a file is executing. Use callbacks on Workers to filter execution by status (can be HTTPs status) and close the socket listener while some callback isn't triggered or some state (some storage or variable) isn't filled by certain value.
Take the example from MDN page about Web Workers:
example.html: (the main page):
var myWorker = new Worker('my_task.js');
myWorker.onmessage = function(oEvent) {
//take current status from the worker from oEvent
status = oEvent.status;
console.log('Worker said : ' + oEvent.status);
};
//if ok, send an order to continue receiving php calls
if (status == 200)
//or other function
myWorker.postMessage('someorder');
my_task.js (the worker):
postMessage("Worker listening");
onmessage = function(oEvent) {
//if status is not ok, worker is busy and can't do anything
if (status != 200)
postMessage('Hi ' + oEvent.data);
};
You were so general that it's the only thing that came within my mind to solve your problem.
Related
To start off this is what I am trying to accomplish:
I am trying to do file copies to an array of servers. There are several steps that must be completed in a specific order before and after these copies (for example, stopping IIS, backing up and clearing folders, running a bat file, etc) so they are not single operations.
To make this super easy I wrote an API in node.js that does simple tasks like copy files and folders, delete folders, etc. I then wrote a frontend in node.js using an express generator and Pug that uses javascript XMLHhttpRequests to send commands to the API depending on what I needed to do. I have the API written and running as well as the frontend. Now on to the problems:
If I have my XMLHttpRequest run in synchronous mode (example: xhttp.open("POST", url , false);) when the command is sent to the API to copy a folder if the folder takes several minutes to copy the browser freezes. Chrome displays a "Page Frozen" error. However, the job gets done correctly.
If I have my XMLHttpRequest run in asynchronous mode (example: xhttp.open("POST", url , true);) then every command gets sent to the API at once so that the fastest operation completes first and the commands are out of order. The copy will fail.
I've tried searching for a way to make it so that each operation sent from the frontend javascript has to return a SUCCESS (or 200 response) from the API before moving on to the next command but so far all I've seen is "just use synchronous". Right now that's what I'm doing. That doesn't seem like the best solution even though it works. Is there a better way to do this in a way that won't freeze the browser?
I figured this out by writing a function to handle the requests, setting a counter (for the steps of the process), and putting a switch statement in the if statement for the result. It wasn't exactly what I needed but the basics of my solution is in the answers to this question: How can I call ajax synchronously without my web page freezing
Here's what I did in case it helps anyone else who finds this question:
function myFunction (step, params, url) {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
switch(step) {
case 2:
//url and params are set here, and step 2 is done here
myFunction(step, params, url);
break;
case 3:
// and so on and so forth
}
}
xhttp.open("POST", url , true);
xhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xhttp.send(params);
step++;
}
//kick off the function
var step = 1;
var url = "my URL to the API with call";
var parameters = "my parameters";
myFunction(step, parameters, url);
We have written a custom spawner for JupyterHub to suit our use cases. In the same spawner, we have memory limits for every user, and this is checked within the poll() function, and logged on the server.
What I want to do is to display an alert to the client when he approaches, say about 90% of his memory limits, and another at 100%, displaying that the process is being killed.
Simply put : I need to display an alert message on client browser window through the poll() function
Is it even possible ? Can I do it using Flask ? (The resources I found online were about creating a new server. In this case, we already have a jupyterhub server running.)
EDIT : Here's my client side Javascript:
<script type="text/javascript">
// Client-side Javascript in the HTML
var targetContainer = document.getElementById("this-div");
var eventSource = new EventSource("/stream");
eventSource.onmessage = function(e) {
targetContainer.innerHTML = e.data;
};
</script>
Here's the poll() function :
#gen.coroutine
def poll(self):
"""Poll the spawned process to see if it is still running.
If the process is still running, we return None. If it is not running,
we return the exit code of the process if we have access to it, or 0 otherwise.
"""
self.log.debug("Polling " + self.user.name + "...")
# peh = ProxyErrorHandler()
# peh.get(503)
self.stream()
And here's the stream() function:
app = Flask(__name__)
#app.route("/stream")
def stream(self):
def eventStream():
while True:
yield "Hello World"
return Response(eventStream(), mimetype="text/event-stream")
The Javascript throws a 404 Not Found error, which makes sense because the poll() function runs every 30 seconds only.
Is there a way I can run a php function through a JS function?
something like this:
<script type="text/javascript">
function test(){
document.getElementById("php_code").innerHTML="<?php
query("hello"); ?>";
}
</script>
<a href="#" style="display:block; color:#000033; font-family:Tahoma; font-size:12px;"
onclick="test(); return false;"> test </a>
<span id="php_code"> </span>
I basically want to run the php function query("hello"), when I click on the href called "Test" which would call the php function.
This is, in essence, what AJAX is for. Your page loads, and you add an event to an element. When the user causes the event to be triggered, say by clicking something, your Javascript uses the XMLHttpRequest object to send a request to a server.
After the server responds (presumably with output), another Javascript function/event gives you a place to work with that output, including simply sticking it into the page like any other piece of HTML.
You can do it "by hand" with plain Javascript , or you can use jQuery. Depending on the size of your project and particular situation, it may be more simple to just use plain Javascript .
Plain Javascript
In this very basic example, we send a request to myAjax.php when the user clicks a link. The server will generate some content, in this case "hello world!". We will put into the HTML element with the id output.
The javascript
// handles the click event for link 1, sends the query
function getOutput() {
getRequest(
'myAjax.php', // URL for the PHP file
drawOutput, // handle successful request
drawError // handle error
);
return false;
}
// handles drawing an error message
function drawError() {
var container = document.getElementById('output');
container.innerHTML = 'Bummer: there was an error!';
}
// handles the response, adds the html
function drawOutput(responseText) {
var container = document.getElementById('output');
container.innerHTML = responseText;
}
// helper function for cross-browser request object
function getRequest(url, success, error) {
var req = false;
try{
// most browsers
req = new XMLHttpRequest();
} catch (e){
// IE
try{
req = new ActiveXObject("Msxml2.XMLHTTP");
} catch(e) {
// try an older version
try{
req = new ActiveXObject("Microsoft.XMLHTTP");
} catch(e) {
return false;
}
}
}
if (!req) return false;
if (typeof success != 'function') success = function () {};
if (typeof error!= 'function') error = function () {};
req.onreadystatechange = function(){
if(req.readyState == 4) {
return req.status === 200 ?
success(req.responseText) : error(req.status);
}
}
req.open("GET", url, true);
req.send(null);
return req;
}
The HTML
test
<div id="output">waiting for action</div>
The PHP
// file myAjax.php
<?php
echo 'hello world!';
?>
Try it out: http://jsfiddle.net/GRMule/m8CTk/
With a javascript library (jQuery et al)
Arguably, that is a lot of Javascript code. You can shorten that up by tightening the blocks or using more terse logic operators, of course, but there's still a lot going on there. If you plan on doing a lot of this type of thing on your project, you might be better off with a javascript library.
Using the same HTML and PHP from above, this is your entire script (with jQuery included on the page). I've tightened up the code a little to be more consistent with jQuery's general style, but you get the idea:
// handles the click event, sends the query
function getOutput() {
$.ajax({
url:'myAjax.php',
complete: function (response) {
$('#output').html(response.responseText);
},
error: function () {
$('#output').html('Bummer: there was an error!');
}
});
return false;
}
Try it out: http://jsfiddle.net/GRMule/WQXXT/
Don't rush out for jQuery just yet: adding any library is still adding hundreds or thousands of lines of code to your project just as surely as if you had written them. Inside the jQuery library file, you'll find similar code to that in the first example, plus a whole lot more. That may be a good thing, it may not. Plan, and consider your project's current size and future possibility for expansion and the target environment or platform.
If this is all you need to do, write the plain javascript once and you're done.
Documentation
AJAX on MDN - https://developer.mozilla.org/en/ajax
XMLHttpRequest on MDN - https://developer.mozilla.org/en/XMLHttpRequest
XMLHttpRequest on MSDN - http://msdn.microsoft.com/en-us/library/ie/ms535874%28v=vs.85%29.aspx
jQuery - http://jquery.com/download/
jQuery.ajax - http://api.jquery.com/jQuery.ajax/
PHP is evaluated at the server; javascript is evaluated at the client/browser, thus you can't call a PHP function from javascript directly. But you can issue an HTTP request to the server that will activate a PHP function, with AJAX.
The only way to execute PHP from JS is AJAX.
You can send data to server (for eg, GET /ajax.php?do=someFunction)
then in ajax.php you write:
function someFunction() {
echo 'Answer';
}
if ($_GET['do'] === "someFunction") {
someFunction();
}
and then, catch the answer with JS (i'm using jQuery for making AJAX requests)
Probably you'll need some format of answer. See JSON or XML, but JSON is easy to use with JavaScript. In PHP you can use function json_encode($array); which gets array as argument.
I recently published a jQuery plugin which allows you to make PHP function calls in various ways: https://github.com/Xaxis/jquery.php
Simple example usage:
// Both .end() and .data() return data to variables
var strLenA = P.strlen('some string').end();
var strLenB = P.strlen('another string').end();
var totalStrLen = strLenA + strLenB;
console.log( totalStrLen ); // 25
// .data Returns data in an array
var data1 = P.crypt("Some Crypt String").data();
console.log( data1 ); // ["$1$Tk1b01rk$shTKSqDslatUSRV3WdlnI/"]
I have a way to make a Javascript call to a PHP function written on the page (client-side script). The PHP part 'to be executed' only occurs on the server-side on load or refreshing'. You avoid 'some' server-side resources. So, manipulating the DOM:
<?PHP
echo "You have executed the PHP function 'after loading o refreshing the page<br>";
echo "<i><br>The server programmatically, after accessing the command line resources on the server-side, copied the 'Old Content' from the 'text.txt' file and then changed 'Old Content' to 'New Content'. Finally sent the data to the browser.<br><br>But If you execute the PHP function n times your page always displays 'Old Content' n times, even though the file content is always 'New Content', which is demonstrated (proof 1) by running the 'cat texto.txt' command in your shell. Displaying this text on the client side proves (proof 2) that the browser executed the PHP function 'overflying' the PHP server-side instructions, and this is because the browser engine has restricted, unobtrusively, the execution of scripts on the client-side command line.<br><br>So, the server responds only by loading or refreshing the page, and after an Ajax call function or a PHP call via an HTML form. The rest happens on the client-side, presumably through some form of 'RAM-caching</i>'.<br><br>";
function myPhp(){
echo"The page says: Hello world!<br>";
echo "The page says that the Server '<b>said</b>': <br>1. ";
echo exec('echo $(cat texto.txt);echo "Hello world! (New content)" > texto.txt');echo "<br>";
echo "2. I have changed 'Old content' to '";
echo exec('echo $(cat texto.txt)');echo ".<br><br>";
echo "Proofs 1 and 2 say that if you want to make a new request to the server, you can do: 1. reload the page, 2. refresh the page, 3. make a call through an HTML form and PHP code, or 4. do a call through Ajax.<br><br>";
}
?>
<div id="mainx"></div>
<script>
function callPhp(){
var tagDiv1 = document.createElement("div");
tagDiv1.id = 'contentx';
tagDiv1.innerHTML = "<?php myPhp(); ?>";
document.getElementById("mainx").appendChild(tagDiv1);
}
</script>
<input type="button" value="CallPHP" onclick="callPhp()">
Note: The texto.txt file has the content 'Hello world! (Old content).
The 'fact' is that whenever I click the 'CallPhp' button I get the message 'Hello world!' printed on my page. Therefore, a server-side script is not always required to execute a PHP function via Javascript.
But the execution of the bash commands only happens while the page is loading or refreshing, never because of that kind of Javascript apparent-call raised before. Once the page is loaded, the execution of bash scripts requires a true-call (PHP, Ajax) to a server-side PHP resource.
So, If you don't want the user to know what commands are running on the server:
You 'should' use the execution of the commands indirectly through a PHP script on the server-side (PHP-form, or Ajax on the client-side).
Otherwise:
If the output of commands on the server-side is not delayed:
You 'can' use the execution of the commands directly from the page (less 'cognitive' resources—less PHP and more Bash—and less code, less time, usually easier, and more comfortable if you know the bash language).
Otherwise:
You 'must' use Ajax.
I'm currently have an issue creating a webapp. All of the pages that we are creating can be viewed through a function that gets the post data and displays it onto the page. The issue I'm having is that when loading the content, the corresponding JS for sockets does not execute.
I believe this is because we're using:
socket.on("connect")
and the connect event would only fire once, but I'm unsure about how to fix this.
An example of the JS I'm currently using can be seen below.
function runJs(){
var url = document.location.pathname.toLowerCase();
if(url == '/account/create'){
var socket = io();
//once the socket connects, make calls
socket.on("connect", function(){=
socket.on("accountCreated", function(data){
if(typeof data.data.error !== "undefined"){
jQuery("#error").text(data.data.error);
}
else{
//account creation was successful and we're logged in.
//redirect to the home page
window.location.href = "/";
}
});
});
}
When executing another function (not posted here, as it's not important), it updates the pages HTML and runs the runJs() function seen above. I have confirmed through console.log that the function is indeed being called, but the code within the socket.on does not execute unless the page is reloaded.
Does anyone have any ideas about how I could fix this?
Disclaimer
Firstly, a disclaimer: I am working within specific boundaries, so whilst it may seem I'm going about something the long way round, I am limited as to what I can do. I know I should be doing this entirely differently, but I cannot. If it's not possible to do what I'm trying to do here, then that's fine, I just need to know.
Background
Basically, this boils down to a cross-domain javascript call. However, I need to wait for the response before returning the method.
Say I have a page - example1.com/host.html. This contains a javascript method of 'ProvideValue()' which returns an int. Edit: This method must be executed where it is found, since it may need to access other resources within that domain, and access global variables set for the current session.
https://example1.com/host.html
function ProvideValue(){
return 8; // In reality, this will be a process that returns a value
}
This host.html page contains an iframe pointing to example2.com/content.html (note the different domain). This content.html page contains a method that needs to display the value from host.html in an alert.
https://example2.com/content.html
function DisplayValue(){
var hostValue = //[get value from ProvideValue() in host.html]
alert(hostValue);
}
That's it.
Limitations
I can run any javascript I like on the host.html, but nothing server-side. On content.html I can run javascript and anything server-side. I have no control over the example1.com domain, but full control over example2.com.
Question
How can I retrieve the value from ProvideValue() on example1.com/host.html within the DisplayValue() method on example2.com/content.html?
Previous Attempts
Now, I've tried many of the cross-domain techniques, but all of them (that I've found) use an asynchronous callback. That won't work in this case, because I need to make the request to the host.html, and receive the value back, all within the scope of a single method on the content.html.
The only solution I got working involved relying on asynchronous cross-domain scripting (using easyXDM), and a server-side list of requests/responses in example2.com. The DisplayValue() method made the request to host.html, then immediately made a synchronous post to the server. The server would then wait until it got notified of the response from the cross-domain callback. Whilst waiting, the callback would make another call to the server to store the response. It worked fine in FireFox and IE, but Chrome wouldn't execute the callback until DisplayValue() completed. If there is no way to address my initial question, and this option has promise, then I will pose this as a new question, but I don't want to clutter this question with multiple topics.
Use XMLHttpRequest with CORS to make synchronous cross-domain requests.
If the server doesn't support cors, use a proxy which adds the appropriate CORS headers, e.g. https://cors-anywhere.herokuapp.com/ (source code at https://github.com/Rob--W/cors-anywhere).
Example 1: Using synchronous XHR with CORS
function getProvidedValue() {
var url = 'http://example.com/';
var xhr = new XMLHttpRequest();
// third param = false = synchronous request
xhr.open('GET', 'https://cors-anywhere.herokuapp.com/' + url, false);
xhr.send();
var result = xhr.responseText;
// do something with response (text manipulation, *whatever*)
return result;
}
Example 2: Use postMessage
If it's important to calculate the values on the fly with session data, use postMessage to continuously update the state:
Top-level document (host.html):
<script src="host.js"></script>
<iframe name="content" src="https://other.example.com/content.html"></iframe>
host.js
(function() {
var cache = {
providedValue: null,
otherValue: ''
};
function sendUpdate() {
if (frames.content) { // "content" is the name of the iframe
frames.content.postMessage(cache, 'https://other.example.com');
}
}
function recalc() {
// Update values
cache.providedValue = provideValue();
cache.otherValue = getOtherValue();
// Send (updated) values to frame
sendUpdate();
}
// Listen for changes using events, pollers, WHATEVER
yourAPI.on('change', recalc);
window.addEventListener('message', function(event) {
if (event.origin !== 'https://other.example.com') return;
if (event.data === 'requestUpdate') sendUpdate();
});
})();
A script in content.html: content.js
var data = {}; // Global
var parentOrigin = 'https://host.example.com';
window.addEventListener('message', function(event) {
if (event.origin !== parentOrigin) return;
data = event.data;
});
parent.postMessage('requestUpdate', parentOrigin);
// To get the value:
function displayValue() {
var hostName = data.providedValue;
}
This snippet is merely a demonstration of the concept. If you want to apply the method, you probably want to split the login in the recalc function, such that the value is only recalculated on the update of that particular value (instead of recalculating everything on every update).