I know how to run a script with a cron, but what I need is to be able to run my script only by a cron.
Thank you!
You should keep this script outside of the public folder. Also, set appropriate permissions to the file so public users can not execute the script.
Put below code snippet to the top of your script.
if(php_sapi_name() !== 'cli'){
die('Can only be executed via CLI');
}
Note that you need to use the full path to the PHP executable when you setup your cron job.
Ex : /usr/local/bin/php (Your path may be differ from this)
As explained in this duplicate thread:
PHP & cron: security issues
You should keep this file outside of public_html.
Sometimes, though, this is not possible. My mind went to Moodle, where a similar feature exists. This is what they do.
From cron.php:
...
/// The current directory in PHP version 4.3.0 and above isn't necessarily the
/// directory of the script when run from the command line. The require_once()
/// would fail, so we'll have to chdir()
if (!isset($_SERVER['REMOTE_ADDR']) && isset($_SERVER['argv'][0])) {
chdir(dirname($_SERVER['argv'][0]));
}
...
/// check if execution allowed
if (isset($_SERVER['REMOTE_ADDR'])) { // if the script is accessed via the web.
if (!empty($CFG->cronclionly)) {
// This script can only be run via the cli.
print_error('cronerrorclionly', 'admin');
exit;
}
// This script is being called via the web, so check the password if there is one.
if (!empty($CFG->cronremotepassword)) {
$pass = optional_param('password', '', PARAM_RAW);
if($pass != $CFG->cronremotepassword) {
// wrong password.
print_error('cronerrorpassword', 'admin');
exit;
}
}
}
...
You need a PHP CLI/CGI executable for that. Assuming that the php program is located at /usr/local/bin/php, you can use:
/usr/local/bin/php /path/to/your/script.php
See also: http://nl.php.net/manual/en/features.commandline.usage.php
Please add this script at the top of your PHP file:
$isCLI = ( php_sapi_name() == 'cli' );
if( !$isCLI )
die("Sorry! Cannot run in a browser! This script is set to run via cron job");
and then if you try to run the PHP file via the browser, you cannot run it. This error message will be displayed. But at the same time, it can be run via a cron job.
Try to grant execute permissions only for the cron daemon user, maybe with that you get what you want.
Regards!
Related
I have a PHP script that essentially copies a zip file, unzips it, and then copies the resulting text files to a MySQL database.
This works perfectly when I call my php page manually, but this needs to be done every day, so I want to set this up as a cron job.
I have a cron job that works, and I have verified that by calling a very simple script, but it fails when trying to run my full page.
I have tracked this down to two areas of code. Firstly:
date_default_timezone_set('Europe/London');
I understand that I can set this up through an htaccess or php.ini file, so I am not concerned about this one.
However, the second area of code that is stopping the cron job from running is:
$localzipfile = "myfolder/myzipfile.zip";
$localzipfilefullpath = "/homepages/20/dXXXXXXXXX/htdocs/sub/folder/" . $localzipfile . "";
$localpath = pathinfo(realpath($localzipfile), PATHINFO_DIRNAME);
$zip = new ZipArchive;
$res = $zip->open($localzipfilefullpath);
if ($res === TRUE) {
$zip->extractTo($localpath);
$zip->close();
}
Again, this all works perfectly when I run the code manually, so I know everything is in place and works. All paths are correct, and the zip file unzips as expected.
It is only when I try to run this as a cron job that it fails and doesn't unzip the file.
I have seen several other SO questions about php files that run manually but don't run as cron jobs, but none that relate to the unzipping of a local zip file.
UPDATE:
I have managed to log the error output from the cronjob, and it is reporting this:
"Cannot instantiate non-existent class: ziparchive"
I don't understand this, though, as the code all runs without issue when I run it from the browser?
Are you using relative pathes for $localzipfile and $localpath?
If yes, try to use absolute ones or write a shell script that chdirs into the PHP script's directory before running PHP.
The paths to your file need to be absolute, for example:
$localzipfile = "/home/myfolder/myzipfile.zip";
$localzipfilefullpath = "/var/www/html/homepages/20/dXXXXXXXXX/htdocs/sub/folder/" . $localzipfile;
Are you sure that the user running cron has permissions to access both directories? Cron might run under a different user which cannot access your /myfolder or /html dir, so make sure to give the users apropriate rights. You can see those two answers Answer1 | Answer2 I posted some time back on how to set up permissions.
Finally managed to get to the bottom of this, after much testing and investigating!
Thanks to all who gave suggestions, but it seemed that when I was running the script through a browser, it was running at PHP version 5.4, but when the cron job was running, it was running at version 4.9!
Changing my cronjob calling script from:
0 * * * * /usr/bin/php
to
0 * * * * /usr/bin/php5
solved the zip problem, and the cronjob now unzips my file correctly!
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;
}
Hey, I'm trying to use PHP to execute a shell command which will run remotely run a server on my box. Here is my PHP Code:
if ($key == "test") { echo "<font color='green'>Key is valid. Server satrted.</font>";
$start = system('cd /root/st/; ls;');
}
The problem is, the ls command runs from the same directory as the web server, which returns all of the files from /var/www/html instead of /root/st/. I have also tried the chdir command to no avail. Anyone know how you would get the directory to change so that the command could be run from a specified directory? Thanks.
Does the user that PHP is running as (eg, the user invoking the CLI script) have permission to read the directory? If you're going into /root/ but aren't root, you'd need to either add cd to sudoers for the current user, or choose another directory.
Edit: note that adding cd to sudoers is not even remotely okay for anything other than a local, you-only script. :)
There are two ways I would approach this.
1: use proper unix commands, and see if they work. IE:
if ($key == "test") { echo "<font color='green'>Key is valid. Server satrted.</font>";
$start = system('ls /root/st/');
}
2: Make it run a script on the system, that can go outside the webserver's chroot.
if ($key == "test") { echo "<font color='green'>Key is valid. Server satrted.</font>";
$start = system('server.sh');
}
and server.sh is
#!/bin/bash
cd /root/st
ls
PHP has a chdir() function. Not sure if it applies to exec/system calls, but worth a try.
Store the location in a variable, say $loc = '/root/st' and then do ls $loc in your code. Hope this helps.
Your problem is not the directory the script is running in (or more precisely the current working directory of the user running the script), but that cd /root/st/ will fail on any reasonable configured UNIX/Linux system. /root is usually owned by root and can't be accessed by any other user.
Using you snippet this will silently fail because you unconditionally chained the cd and the ls commands with a semicolon instead of &&.
I have a php script:
$extract_dir = "./";
$extract_file = "extractME.zip";
$zip = new ZipArchive;
$res = $zip->open($extract_file);
if ($res === TRUE) {
$zip->extractTo($extract_dir);
$zip->close();
echo "ok";
} else {
echo "failed";
}
But when I execute this script, via http://www.mywebsite.com/extract.php
All the files on FTP are show with OWNER 'root', but not the user ex . 'neo' as it should be. So the user cant edit/rename/delete these files.
Is it possible to fix this anyhow (I own the server), that files will be extracted with 'USERNAME' OWNERSHIP ?
ozzwanted, for some reason your web server (apache) is running as root so any file it makes will be made as root. This should never be the case. apache usually runs as 'www-data' or 'httpd', or 'nobody' or 'god' depending on the linux distro.
I suggest you look into this from a sysadmin point of view and have someone sort it out for you before you end up getting exploited. (assuming this is a live server)
You can use www.php.net/chown function or your can run a 'chown' command on the command line or do it from PHP with something like system() or exec() functions.
Good luck.
It extract as the user running the webserver (note: you should not be running it as root). Try using chown.
I'm using the following command to execute a PHP file via cron
php -q /home/seilings/public_html/dvd/cron/mailer.php
The problem is that I Have a file that's included in the execution that determines which config to load.... such as the following:
if (!strstr(getenv('HTTP_HOST'), ".com")) {
$config["mode"] = "local";
} else {
$config["mode"] = "live";
}
The cron is loading the LOCAL config when it should be loading the LIVE config. I've tried using the http:// URL to the file instead of the absolute path but it didn't find the file. Do I need to change the command to use a URL within it?
Another simple solution:
cron:
php -q /home/seilings/public_html/dvd/cron/mailer.php local
php:
if (!empty($argv[0])) {
$config["mode"] = "local";
} else {
$config["mode"] = "live";
}
Use this php_sapi_name() to check if the script was called on commandline:
if (php_sapi_name() === 'cli' OR !strstr(getenv('HTTP_HOST'), ".com")) {
$config["mode"] = "local";
} else {
$config["mode"] = "live";
}
If you want to use "live" on the commandline use this code:
if (php_sapi_name() === 'cli' OR strstr(getenv('HTTP_HOST'), ".com")) {
$config["mode"] = "live";
} else {
$config["mode"] = "local";
}
When you run the php with cron it is very likely that then environment variable 'HTTP_HOST' will not be set (or null) and when null is given to strstr function, strstr returns false that is why the mode is set to "local".
You're probably getting a different set of environment variables when you execute your command via cron, versus the command line. You might need to write a wrapper script that sets the environment up the way you want it before running your PHP command.
Enviroment variable such as HTTP_HOST exists only when you're running php scrints under web server. But you can add it manually in your crontab config:
## somewhere in crontab config
HTTP_HOST=somthing.com
15 * * * * /path/to/your/script > /dev/null 2>&1
This will enable your script to think that it's running on production enviroment.
If you're feeling lazy and do not feel like making sure all those env variables work you might want to try running with cron using:
lynx -dump http://url.to.your.script > /dev/null