I need to allow php scripts to be called only via Ajax and Cron, and not called via it's address in the browser.
In F12 all the php scripts are visible, and any user may call the php script like website.com/file.php
I need to allow php scripts to be called only via Ajax and Cron, and not called via it's address in the browser.
In F12 all the php scripts are visible, and any user may call the php script like website.com/file.php
You cannot. Scripts do not know how they are called; all they know is that the web server has them invoked.
And the web server does not know who is it that is calling, just that a request came by on the HTTP or HTTPS port (cron CLI is an exception, see below).
The best you can do is verify these two headers:
HTTP_USER_AGENT either empty or filled
HTTP_X_REQUESTED_WITH either 'XMLHttpRequest' or not (possibly empty)
The results will be:
UA empty, XRW empty cron or a browser faking cron
UA "Lynx" or "wget", XRW empty cron calling wget or lynx (or curl?)
UA empty, XRW filled some prankster messing with you (*)
UA filled, XRW filled AJAX call
UA filled, XRW empty browser
(*) or some "privacy" client firewall removing the User-Agent header
But do remember that:
curl)You would be better off checking e.g.
HTTP_REMOTE_ADDR
which is not set when calling via cron CLI, and when set, should be the IP address of the servers you authorize, as seen by the Web server.
Another possibility is to use authentication, e.g. via challenge/response with a shared secret between the calling script and the called PHP program.
I'm going out on a limb here, and imagining that your situation is this:
You have a script that you need to be called periodically, or when a user does something via AJAX, but not too often (maybe because it's computationally expensive). So you call the script from cron once a day, and whenever some user looks at a page, but do not want the user to see the call and be able to replicate it at will, maybe even from a different browser or a cron of their own.
A simple solution is to do it the other way round. You can set a variable in the session:
// AJAX calls are only allowed every 600 seconds PER EACH USER
// (you should verify that a login exists)
if (array_key_exists('ajax', $_SESSION)) {
if (time() - $_SESSION['ajax'] < 600) {
return;
}
}
$_SESSION['ajax'] = time();
Or you can limit the calls using a file:
if (file_exists('call.txt')) {
if ((time() - filemtime('call.txt')) < 600) {
return;
}
}
touch('call.txt');
Now the script cannot be called more often than once every 600 seconds (10 minutes), no matter how (except for cron CLI which will almost surely create the call.txt in a different directory).
You can perhaps also store the script output in a file, and read the file's contents if it's not older than a given value. So you can issue one thousand AJAX calls, but only the first will do any actual work - the other will wait on the locked file and then read a cached copy. This is trickier than it appears due to the need of dealing with race conditions between possibly several parallel calls.
XHR tab. So, a user may just click on php file and call it, just for fun. BTW this is also the question- how to prevent them from being visible?