This could be a kind of strange question. I have a php file in a public web site where I have access to the server. For the moment we do not need to set Cron job for this file execution. However I need to limit the execution of this file only via localhost. I don't have any precise idea about the way should I do this. Is there any way to detect whether the request is localhost or not? I mean with PHP. Or should I need to handle this via security setting or firewall of the server?
I'm assuming you mean you want to be able to execute the script only from the server, and not via the web from another host. You have two options:
Option 1
move it out of the public_html folder. There is no reason you should not take this option, unless there is something preventing you from doing so. In that case,
Option 2:
Wrap the entire code in the following if statement
if (php_sapi_name() == 'cli')
{
//your code
}
Alternatively,
if (php_sapi_name() != 'cli')
die();
//your code
This ensures your script will only run if invoked from the command line, and not via the web.
You could check IP addresses like this:
if($_SERVER["REMOTE_ADDR"]!=$_SERVER["SERVER_ADDR"])
{
exit;
}
Related
Is there a way to call a script from a cron job only and make it so no other ips can run that script?
I have a script that sends notifications to phones. It is supposed to be called by a cron job once day, but sometimes something triggers it and everyone gets notified when they shouldn't. I would like to limit it to be called from my server only.
In other words to make it not to be able to be called from a browser or a spider etc..
Thanks
I'd suggest that you don't make this file available publicly.
But to answer your question directly; A way to do this is to add the following check:
if (php_sapi_name() === 'cli') {...}
More info: https://secure.php.net/manual/en/function.php-sapi-name.php
Your script seems to be available via public URL. Move it somewhere else. For example, if the script is within /www/site.com/public/script.php, and /www/site.com/public is the public directory of the Web server, move it to some /www/site.com/cron/script.php. Make sure that the Web server is not configured to fetch files from the cron directory.
As others have written, there may be other setups you could use, (permissions and file locations) however, I've never been someone who tells someone to re-engineer their whole process to meet a single need. That feels too much like the tail wagging the dog. Therefore, if you wish to have a script that can only be executed by your cron job and not mistakenly by another process, I would offer you this solution
The php_sapi solution has been noted to provide inconsistent behavior and is system configuration specific (for example echo it's output when calling your script from the command line, and again when calling from a cron). This can lead to tracking down other bugs. The best solution I have seen and used, is to pass a command line argument to your script and evaluate the existence of that argument.
your cron job would look something like:
* * * * * * php /path/to/script --cron
Then, inside your script you would perform an if check, that when not satisfied, stops the script.
if( $argv[0] != 'cron')
{
//NO CRON ARGUMENT SUPPLIED, SOMETHING ELSE MUST BE CALLING THIS
exit;
}
Take not that some systems may use the first argument as the script name, so based on your individual system configuration, you may need to check $argv[1]
Hope this helps, let me know if you have any questions, I'm happy to respond or edit if needed.
Each time when I am opening e.g. retrieveContent.php the script is executed and insert records into the database. Since I use this script in a schedule job it should not be a problem.
However I noticed that a user found the script path and did opened the retrieveContent.php file which was executed and inserted a record in the database.
How can I prevent browser transactions by a user using PHP? Thanks in advance!
Look at the php_sapi_name() function. It will tell you if you're running in CLI (command-line interface).
http://php.net/manual/en/function.php-sapi-name.php
You can also move the PHP script to somewhere outside of your web server's document tree.
You have lots of options. I'll mention just three:
Append a query parameter, that only you know and that is hard-coded in the script, e. g. retrieveContent.php?key=secret. (Or in CLI mode, a secret command line argument.) Check this parameter in your script and only perform the actions if it matches the hard-coded value.
If your scheduled job is performed on the same server where the script resides, move the script to a separate directory protected by a .htaccess file with the following content:
Deny from all
Allow from localhost
If your scheduled job fetches the script via HTTP, figure out, which user agent is sent in $_SERVER['HTTP_USER_AGENT'], and only perform the actions if the script is accessed by that user agent. But this is less safe, since the user can fake the user agent (if he manages to find out the correct one).
Pass a secret argument to your script when called via CLI and confirm it on PHP side. For example:
-- terminal --
php script.php secret-argument
-- script.php --
<?php
if(!isset($argv[1]) || $argv[1] != 'secret-argument')
{
die('restricted access');
}
// Rest of script
$argv is a global PHP variable that Contains an array of all the arguments passed to the script when running from the command line.
Couple of ways this could be done:
if(php_sapi_name() != 'cli'){ die();} or if(PHP_SAPI != 'cli'){ die();}
The following solutions won't always work depending on server settings:
Check for $_SERVER['argv'], it is only set on CLI execution if (empty($_SERVER['argv'])) { die();}. This is mostly true, unless your server loads those on HTTP request.
if(!empty($_SERVER['REMOTE_ADDR'])) { die();} REMOTE_ADDR is empty when called via CLI.
if(empty($_SERVER['TERM'])) { die();} PHP loads the TERM variable with the terminal type. Same is true for $_SERVER['SHELL'] or $_SERVER['USER'].
I am running a PHP script via linux cronjob and I want to make sure that it can be run remotely only from the computer whose ip address I specify, plus via cronjob.
Now, I can check the remote ip addresses from $_SERVER['REMOTE_ADDR'], but doing so would also stop execution via cronjob.So, how to make both things work?
You'll need to check if it is run from the command-line too to handle the cron case
if (php_sapi_name() == 'cli' || $_SERVER['REMOTE_ADDR'] == 'your.ip.add.ress') {
// allow
}
Put the cronjob out of your web root.
Then you can check wheather the cron is running over a cli:
if (php_sapi_name() != 'cli') {
die();
}
Its no good idea to tun your cron over your webserver. Then every people can start it.
You can use php_sapi_name function to check for local (cron) execution in addition to checking IP addresses, something like this:
if (php_sapi_name() == 'cli' || $_SERVER['REMOTE_ADDR'] == 'xxx.yyy.zzz.vvv') {
//do your stuff
}
else {
/show some error
}
That said, you need to remember that remote address can be easily spoofed, therefore it's not good to rely on it, at least if the server is open to the internet. It's a bit more secure if you're running on a local network.
I'm writing a PHP script that I want to disable from web access (I will ask users to move it out of the web root and execute via CLI, but you never know if they'll listen!)
Is there a simple function that occurs to anyone to make the page die if it's requested by a browser?
Thanks for any ideas.
You could test whether the script is being run through the CLI using php_sapi_name().
It can return a whole bunch of different possible values when run on a HTTP server - difficult to make a reliable distinction there - but there seems to be only one possible return value for the CLI: cli.
If you're looking for an all-purpose solution, make sure you read the comment thread below for more detailed discussion on some potential gotchas.
'PHP_SELF' The filename of the
currently executing script, relative
to the document root. For instance,
$_SERVER['PHP_SELF'] in a script at
the address
http://example.com/test.php/foo.bar
would be /test.php/foo.bar. The
FILE constant contains the full path and filename of the current (i.e.
included) file. If PHP is running as a
command-line processor this variable
contains the script name since PHP
4.3.0. Previously it was not available.
http://www.php.net/manual/en/reserved.variables.server.php
I'm not a PHP expert but you could check the $_SERVER variable ?
You can use php-sapi-name function to detect if script was requested by web server or cli interface.
$sapi_type = php_sapi_name();
if (substr($sapi_type, 0, 3) != 'cli') {
die "You are not using CLI".PHP_EOL;
}
you can use php-sapi-name or you can use the predefined constant which is marginally faster (although you'd never notice!)
<?php
if(PHP_SAPI != 'cli') exit;
// continue
I have a CRON job php script that I just set up not too long ago. However, I noticed that the PHP file executed (without the cron job activating). It appears that it happened when a Google Bot crawled the file, because I noticed that the following engine visited my page:
http://www.google.com/bot.html
My question is:
1) Is it possible, that by crawling my webpage, it could have executed the script?
2) How can I "hide" the CRON file from Google?
3) Would it be smart to place this file in somewhere other than my public_html directory?
Many thanks!
1) of course it is
2) see robots.txt (http://www.searchtools.com/robots/robots-txt.html)
3) yes. but if for some reason you depend on calling it via a http daemon you can use a little trick.
eg. first line of code:
if(!isset($_GET['execute'])
exit;
in your crontab:
http://server.tld/file.php?execute=1
1) If the file is placed in a public web directory, then yes, it could be executed by Googlebot (or any other visitor)
2) You could add a Disallow clause for it in your robots.txt. Any regular user can still go and execute it by visiting if you do this.
3) Yes.
You can use also php-cli. Define if it is cron job:
define('_DOING_CRON_', true);
Then in php file:
if(_DOING_CRON_ && php_sapi_name() != 'cli'){
die("You cannot get here: this is only cron task.");
}
Runifus' answer above solved it for me, however the Cron job command line does not work with the ? in the url to pass the querystring as I learnt here: Cron Jobs calling a PHP script with variables
It should be like so:
http://server.tld/file.php execute=1
also the php condition is missing a closing parenthesis
if(!isset($_GET['execute'])) exit;