Using crontab from php - php

I am having troubles with setting up a server which would allow me to manage cron jobs from PHP scripts.
The idea is: users can create as many tasks as they want with possibility to set alarm(s) for each. After alarm is saved into MySQL database, I want to create a cronjob for that entry on user specified time.
The logic is pretty simple but I am getting frustrated over unix user/file permissions. The problem is, user "www-data" has no permissions to run crontab, thus I cannot use it to manage cronjobs via shell_exec invocation in php scripts. I have read a lot of tutorial/threads on similar issues but without any luck. The closest I could get was that I should make sure www-data user has permissions to run crontab (which I am pretty positive it does not have). However, I put "www-data" user into "crontab" group, I created "cron.allow" file in "/etc/cron.d" directory, but still nothing.
Btw, I am using $output = shell_exec("crontab -u www-data -l") to see if it's working or not (if $output == null then there was an error).
What should I do to make this working? Or should I use a bit different approach (maybe I could have some file writeable by www-data and set somewhere in crontab configuration that it should check for cronjobs in there as well, but I dont know how to do that neither)?

Edit: You could put a modified file into /etc/cron.d which is also read for cron comamnds.
Disclaimer: I've not done this (though I'll be damned if I can remember how I did this last time at all)

It seems that system my app is running on is handling cron.allow/cron.deny files very oddly (at least to my understanding of these files). I deleted /etc/cron.allow file and suddenly www-data user can use crontab command in php scripts. I have no idea why it didn't work with having www-data user stated in cron.allow file, but it looks like it works now.

Related

Running a PHP script that runs a Python script that runs a bash script, hangs on bash

I have a Python script which is encoding a video and then calling a shell script which uploads the new video to dropbox. It works fine from the command line but I needed to make it so others could execute it so I have a PHP script calling the python script.
I don't want the PHP script to run forever (it takes 15-30 mins for it to complete), I just want it to kick off the python script and be done. I figured out what I need to make that happen and like I said it works on the command line. But when it is called via PHP, the video encodes but the file never uploads. I can see the dropbox script was kicked off and is listed as a process using some percent of CPU, that percent never changes, it seems stuck/dead.
the command looks like this, being run using cmd()
script.py -options &>/logs/phptopython.log &
The shell script is kicked off using Popen
Any suggestions?
thanks
It sounds like this could be a permissions issue. Double check the permissions on the directory to which you are trying to upload the video. If you are on Linux you can modify the permissions on that directory like this:
chmod 755 /path/to/dir
This gives the file owner read, write and execute permissions (7). The group and other users get read and execute permissions (5).
Apache is likely running as a different user than when you run the command yourself in bash. A quick test to see if it's a permission issue would be to grant 777 on that directory. I wouldn't leave it that way though – it'd just be a way to quickly identify if permissions are the issue.
If the script works with 777 permissions, you could either change the owner of the directory to the user Apache runs as or add the Apache user to the directory's group and grant the group write permisssions.
Edit:
I just noticed you said you use cmd(), so I'm guessing you are on Windows. My comments might still be relevant but the chmod command won't work on Windows.

Apache runs php scripts as user nobody, cron runs php scripts as user

My default cpanel set up runs apache as user "nobody". So when I run a php script via a browser that outputs a file, that file has ownership nobody:nobody. When I run the script from a cron job logged in as user "fred", the output files are owned by fred:fred
I need both browser and cron to overwrite the same file. The issue I have is that if one "user" creates the file, the other one can't overwrite it.
Please can you let me know where the fundamental problem is and a possible solution. Permissions on the files are 0775.
Do I need to set up groups - adding the user to the same group as nobody? If so how?
How do I get the cron job to run as user nobody?
Many thanks,
Lloyd
Try you code after changing permission of the file as 0777.
But that creates a security issue as anyone can edit your file then.
I have a logic you need to implement to:
Create a shell script that copy the contents of temp file to your actual file.
From PHP you need to update only temp file and Shell can read it as temp file will have read permission for everyone.
Use ssh2_exec command to execute the shell script with your Linux UserName and Password.
For ssh2_exec manual follow this link : http://php.net/manual/en/function.ssh2-exec.php
Hope This will solve your problem.
Ok, my solution to this was to create a crontab for user "nobody".
I've got a standard cpanel installation and so went to /var/spool/cron created an entry for nobody. Ran crontab -e to edit it and install.
Now the php runs as nobody in the cron job exactly the same as if through a browser. All files written belong to nobody with only rw permissions for nobody.

How do I get a PHP file to automatically run itself?

I have a PHP file, x.php, that outputs b.xml every time it is run. The way I do this is by using crontab to run the x.php file. The problem is that due to the server's settings, the new file has permissions of 400. So I also have another crontab line to change file b.xml permissions to 777 so that x.php can run over it next time.
I feel like I am making this too complicated. Is there any way to make this a bit simpler?
Quick Answer
You'll need to chmod the file to be 777 in the x.php script.
After b.xml has been created, run this line:
chmod('path/b.xml', 0777);
Note you should always specify octals when using chmod.
A better way?
When you run a cron job, you should take special note of the user that is running the cronjob.
Generally on a shared server you will have your own login and thus the cron job runs as that user. My question to you - is that user the same as your web server? often php runs as "apache" and cron might be running as "tanner". In that case, setting b.xml to be owned by tanner, and having a permissions 400 means that only tanner can change the file.
To solve this, if you don't have access to umask, one way would be to change your cron job to run as the webserver:
su -c "php /home/jonathan/public_html/b.php" apache
This may or may not work depending if you are allowed to switch to apache as the user. do not forget to switch apache to the actual web servers username.
Now, if that doesn't work, then the alternative is to go for the 777 permissions. Keep in mind on a shared server this means anyone on that server could potentially get to that file if they knew the path.
Another way as suggested by OP:
0,10,20,30,40,50 * * * * /usr/bin/wget http://example.com/user/x.php
This way will always run as the apache (or whatever) user that apache runs as, ensuring the next time it is accessed, the file will be useable.
Ask the server admin to create a new user who owns the folder where the script writes the xml file.
Run your php script through your cron job as such user. If you run your script as the folder's owner you might change the permissions through your php script.
This should work:
// set permission
chmod('path/to/b.xml', 777);
// do other stuff
To solve this issue, I ended up just creating a cronjob such as this:
0,10,20,30,40,50 * * * * /usr/bin/wget http://example.com/user/x.php
This executed the file which created b.xml and since the user who executed the script was public, the permissions remained public as well.

Folder permissions when telling PHP to save a file to that folder?

I'm trying to use this Dagon Design PHP form to help a local non-profit publication enable their readers to submit photos. I've got the "mailer" part working -- the notifications work fine -- but the "saving a file to a folder" part isn't functioning.
On the form page, the author says "the directory must have write permissions," but I'm not sure "who" is writing to that folder -- is this PHP script considered "Owner" when it saves something on my site? Or do I need to allow save permissions for Owner, Group and Others?
I'm not sure why the script isn't saving the photos, but this seems like a good place to start. I've tried looking around on Stack for answers, but most questions seem to have to do with folder creation/permissions.
The page I'm clumsily trying to build is here, if that helps.
As Jon has said already, you don't want to allow write access to everyone.
It's also possible (depending on the hosting) that something like suEXEC is being employed - which will cause your PHP script to run as a user other than the webserver's (as reported by Dunhamzzz).
Probably your best approach, in my opinion, is a script calling whoami:
passthru('whoami');
Or alternatively you could try:
var_dump(posix_getpwuid(posix_geteuid()));
Bear in mind, this does give system information away to the world - so delete the script once you've used it!
Then, as you've correctly asserted in your question, it'll likely be the file permissions.
If you do have CLI access, you can update the permissions safely as so (first command gets the group)
id -n -g <username>
chmod 770 <directory>
chown <username>:<group> <directory>
(You may have to pre-pend "sudo" to the "chown" command above, or find other means to run it as "root"..., reply back if you get stuck.)
If you've not got access to run command-line, you'll presumably be doing this via a (S)FTP client or the alike. I'm afraid the options get a little to broad at that point, you'll have to figure it out (or reply back with the client you're using!)
As always, YMMV.
Finally, bear in mind if this is your own code, people will at some point try uploading PHP scripts (or worse). If that directory is accessible via a public URL ... you're opening the hugest of security holes! (.htaccess, or non-document root locations are your friend.)
If you are not sure how is your server configured (and this would influence who's the final file owner) then add write permission to anyone (chmod a+w folder), upload one file and ls -l to see the owner. Then you can adjust permissions to allow write access to certain users only
The PHP script that saves the files is running with the privileges of some user account on the server; the specific account depends on your OS and the web server configuration. On Linux and when PHP is running as an Apache module this user is the same user that Apache runs as.
Solving your problem reduces to determining which user account we are talking about and then ensuring that this user has permission to write to the save directory (either as owner or as a member of the group; giving write access to everyone is not the best idea).
You'll need to set the permissions of the directory to that of the webserver (probably Apache, nginx or similiar), as that's what is executing the PHP.
You can quickly find out the apache user with ps aux | grep apache, then you want to set the permssions of the upload directory to that user, something like this:
chown -R www-data:www-data images/uploads

Ensure a PHP script is only ever run as a cron job?

How can I ensure a user can not run a PHP script and that it is only ever run as part of a cron job?
You can set an environment variable in your crontab. A line like IS_CRON=1 can be placed at the beginning of your crontab, then check in your php program for get_env("IS_CRON") == 1.
Of course, you should also use file permissions as they're not so easily bypassed. If this is run as part of root's cron, chown root:root yourscript.php and chown 700 yourscript.php.
As ircmaxell says, it'd be better to run as a user other than root assuming you don't need root permissions for what you're doing. I was just taking a guess about your setup.
How about having your PHP script check if $_SERVER['REMOTE_ADDR'] is empty, and if it is not, then have the script exit without doing anything further.
There are probably a number of ways to do this. Off the top of my head, I would say that placing it in a directory owned by root, and only readable by root might get close to achieving the effect you are looking for.
Are there any processes you are looking specifically to restrict it from? If so, using permissions, make it not readable to any of those processes.
I would suggest setting an environment variable within your crontab and then checking for this within your PHP script
Create a user for cron jobs, and set permissions of the script so it can only be run as this user. Of course you then need to put the script in that user's crontab, which you can do by logging in as that user and running crontab. Just don't give that user's password to just any other user...
At first I was also thinking of setting an environment variable which would prevent running this script from the web... But just not putting the script in the space where the web server looks for pages for websites, would do the same.
And nothing is stopping a random user from first setting the environment variable and then running the script.

Categories