I'm in a situation where I personally don't have access to anything but my own public html folder and sub folders, so I have to rely on the guy who owns the account to set up a cron job for me. Neither one of us had ever done this before, so we have been learning through trial and error. The file to run is a php file, but we are trying to run it through the direct path instead of using curl or wget.
At first he was getting emails that said
/usr/local/cpanel/bin/jailshell: /home/[accountname]/public_html/[domain].com/[subfolder]/[filename].php: Permission denied
(The parts in brackets are changed to protect the privacy of the owner.)
After a while the emails stopped coming. I did more googling and realized that first of all, I have to set permissions to execute the file by users other than myself (I assume he is using root), so I edited the chmod to 755. Then I realized that we were trying to access the file directly instead of through php, so I told him to add usr/bin/php before the path to the file. He is editing the crontab through a form in Cpanel rather than using shell, so the minute is 1, all the other time things are * and command is now usr/bin/php /home/[accountname]/public_html/[domain].com/[subfolder]/[filename].php I asked him if he's getting the same error message as before or if something changed, but he said he is no longer receiving any emails at all. So it sounds like cron spontaneously stopped trying to execute the file back when the command was formatted wrong and didn't start again when the usr/bin/php part was added. The php script itself is supposed to add action points to characters in a game and output the number of characters that got points added (if you are already at maximum, you don't count). It has this line in the beginning:
include_once($_SERVER['DOCUMENT_ROOT']."/_private/class_character.inc.php");
I've been thinking that it might have trouble including files because class_character.inc.php in turn contains several includes of other files, which are referred to just by the filename, so the idea is that it would search for them inside _private, but I've been thinking what if it searches for them in where ever the crontab is located instead? However, if there was a problem with the file, the emails would contain warnings or error messages, but it seems it never got as far as running the file in the first place. I assume it can no longer be a permissions issue because chmod is 755. I can run the file by typing in the url, and then it doesn't cause any errors and does what it's supposed to, so if there's anything wrong with the file itself, it's in the scope of includes.
Also I read on one site that the account that the public_html folder is associated with needs to be in a user group called cpaneluser or something like that. But I assume that even if the user group was undefined, it would still be executable now because world right to execute is also set.
Contents of the file it is trying to run:
<?
include_once("../_private/class_character.inc.php");
include_once "../_private/abbr.inc.php";
include_once "../root.inc.php";
$mysqli = new mysqli("localhost", "ACCOUNT", "PASSWORD", "DATABASE");
function getLiveCharacters($mysqli) {
$retArr = array();
$sql = "SELECT `uid` FROM `chars` WHERE `status`=1 ORDER BY `uid`";
$result = $mysqli->query($sql);
if (mysqli_num_rows($result)) {
while ($row = mysqli_fetch_row($result)) {
$retArr[] = $row[0];
}
return $retArr;
}
else return false;
}
function doLoop($mysqli) {
$chars = getLiveCharacters($mysqli);
if (!$chars) return 0;
$counter = 0;
foreach ($chars as $ci) {
$c = new Character($mysqli, $ci);
$result = $c->rest_auto();
if ($result>0) $counter++;
}
return $counter;
}
$result = doLoop($mysqli);
echo $result;
?>
Parts of class_character related
<?
public function rest_auto() {
$oldAP = $this->getAP();
if ($oldAP>=1000) return 0;
$ap = $this->getRestAP();
if ($oldAP+$ap>1000) $ap = max(0, 1000-$oldAP);
$pos = $this->getPosition();
$this->updateCharLocTime($pos->x, $pos->y, $pos->lx, $pos->ly, 0, 5, $ap);
if ($oldAP==-1) {
$sql = "INSERT INTO `char_ap` (`rowID`, `charFK`, `ap`) VALUES (NULL, '$this->uid', '$ap')";
$this->mysqli->query($sql);
}
else if ($ap>0) {
$sql = "UPDATE `char_ap` SET `ap`=`ap`+$ap WHERE `charFK`=$this->uid LIMIT 1";
$this->mysqli->query($sql);
}
return $ap;
}
function getRestAP() {
//automatic resting is triggered once per real life hour
//Starts from 250 AP/rl hour
$ap_rec = 250;
$pos = $this->getPosition();
$curTime = new Time($this->mysqli);
$currentLocation = new GlobalMap($this->mysqli, $pos->x, $pos->y);
$local = new LocalMap($this->mysqli, $pos->x, $pos->y);
$pixArr = $currentLocation->getMajorPixel($currentLocation->x, $currentLocation->y);
$timeofday = $curTime->getTimeofDay($pos->x, $pos->y);
$weather = $curTime->getWeather($pos->x, $pos->y, $timeofday, $currentLocation->getTerrains($pixArr["x"], $pixArr["y"]), $currentLocation->getWaterLevel($pixArr["x"], $pixArr["y"]));
$bodyObj = new Obj($this->mysqli, $this->bodyId);
$blood_per = $bodyObj->getBloodPercentage($this->uid);
//-10 if you don't have a bed
$beds = $local->checkBed($pos->lx, $pos->ly);
if ($beds == -1) $ap_rec -= 10;
//-10 if you don't have shelter
$ap_rec -= 10;//No shelter has been implemented yet
//-10 if it's raining and you don't have shelter
if ($weather["rain"]>0) {
$ap_rec -= 10;
}
//-10 if you are cold
if ($weather["temp"]<16) {
$minus = max($weather["temp"]-16,-10);
$ap_rec += $minus;
}
//-10 if you are too hot
if ($weather["temp"]>36) {
$plus = max(($weather["temp"]-36)*2,10);
$ap_rec -= $plus;
}
//-10 if you're hungry
//Hunger isn't implemented yet
//-10 if you are wounded
if ($blood_per<95) {
$minus = round(($blood_per-96)/2);
$ap_rec += $minus;
}
return $ap_rec;
}
?>
Actually I'm not going to start posting every function that is called in another function because that would take ages. The point is it works when run in the browser, so if something is not compatible when not run through a browser, that is pretty annoying. Of course I could go and change the command to use curl but that still does not explain why it was sending emails in the first place, then stopped.