Execute php script from bash cron job... challenges

software development

#1

I have created a bash auto-notify script.

It is supposed to change directories to a working directory within my user’s file hierarchy. From there, it wgets a file, compares the md5 hash of the file to its previous known md5 hash, and its previous known mod date. If neither the hash nor the mod date have changed, the script does nothing. If something has changed, an email is sent via a php executable.

[code]#!/bin/bash

file: verifychange.sh - an autonotfier script

change to specified directory

cd /home/username/verifyfiles/

Create my variables here at /home/username/verifyfiles/

MYSTAMP=$(date +%Y-%m-%d.%H-%M-%S)

Suffice it say considerable file verification

for the below files is set up in the actual script,

but left out here for brevity’s sake.

OLDHASH=$(more oldhash.txt)
OLDMODDATE=$(more oldmod.txt)

Get the latest file for verification.

wget http://domain.com/myfile.zip
NEWHASH=$(md5sum myfile.zip | awk ‘{ print $1 }’)
NEWMODDATE=$(stat -c %y myfile.zip | awk ‘{ print $1 }’)
if [ “$NEWMODDATE” == “$OLDMODDATE” -a “$OLDHASH” == “$NEWHASH” ]
then
NEWCHECK="OLD"
echo "No change in file."
else
NEWCHECK="NEW"
echo “$NEWHASH” > oldhash.txt
echo “$NEWMODDATE” > oldmod.txt
echo “File has changed.”
# Send static notification email via external php script.
# “$ which php” renders as “/usr/local/php5/bin//php”
# so “/usr/local/php5/bin//php /home/username/usr/local/scripts/notification-email.php”
# doesn’t work from cron either, even though either method works from ssh terminal.
php /home/username/usr/local/scripts/notification-email.php
fi

Log entry.

echo “$MYSTAMP - $NEWCHECK - $NEWMODDATE- $NEWHASH” >> mod.log.txt
rm myfile.zip

Done.[/code]

The whole thing works fine when I call the script directly from the ssh terminal. I even created an alias
alias verifychange="~/usr/local/scripts/verifychange.sh" that works when I call it no matter what directory I’m in at the time.

However, when called from cron, the files created/downloaded/called don’t get placed/accessed in the directory where I’d cd’d into. The oldhash.txt and oldmod.txt files the script asks for are not available.
And php gives me this in my cron daemon email:

The php file is 755 and includes the php shebang at the top of the file.
[php]#!/usr/local/php5/bin//php

<?php #etc. ?>[/php]

I’d be grateful for any help figuring out why it works in ssh from terminal but not from cron.

EDIT: It looks like there may be some answers here:
http://wiki.dreamhost.com/Cron#Executing_a_PHP_Script_with_Crontabs
If you have additional insights, I’d be glad for them as well.

And why on earth would php ‘which’ to /usr/local/php5/bin[color=#FF0000]//[/color]php ???


#2

The environment in cron will have an empty PATH variable.

So it you will need to call programs like so:

OLDHASH=$(/bin/more ~/verifyfiles/oldhash.txt)
/usr/local/bin/php53/bin/php ~/usr/local/scripts/verifychange.sh

Or add
export PATH="/usr/local/bin:/usr/bin:/bin" to the bash script.

The php at /usr/local/bin/php might be 5.2.17 instead of 5.3


#3

Atropos7,

Once again - thank you.

I don’t mind using 5.2 if it isn’t a security risk and won’t drastically affect my script and the results will be the same.

I’ve edited my script as you suggested and actually set this one up almost exactly like it is here:

[code]#!/bin/bash

file: verifychange.sh - an autonotfier script

export PATH…

export PATH="/usr/local/bin:/usr/bin:/bin"

(Elected not to use $LPATH below…)

LPATH=/home/username/verifyfiles

change to specified directory

cd /home/username/verifyfiles/

Create my variables here at /home/username/verifyfiles/

MYSTAMP=$(date +%Y-%m-%d.%H-%M-%S)

Retrieve previous variables from files.

OLDHASH=$(more oldhash.txt)
OLDMODDATE=$(more oldmod.txt)

Get the latest file for verification.

wget -O testfile_10MB http://domain/files/tmp/testfile_10MB
NEWHASH=$(md5sum testfile_10MB | awk ‘{ print $1 }’)
NEWMODDATE=$(stat -c %y testfile_10MB | awk ‘{ print $1 }’)
if [ “$NEWMODDATE” == “$OLDMODDATE” -a “$OLDHASH” == “$NEWHASH” ]
then
NEWCHECK="OLD"
echo "No change in file."
else
NEWCHECK="NEW"
echo “$NEWHASH” > oldhash.txt
echo “$NEWMODDATE” > oldmod.txt
echo “File has changed.”
# Send static notification email via external php script.
# Disabled for simplicity, but works when “NEW” is true.
# php /home/username/usr/local/scripts/notification-email.php
fi

Log entry.

echo “$MYSTAMP - $NEWCHECK - $NEWMODDATE - $NEWHASH” >> mod.log.txt
rm testfile_10MB

Done.

[/code]

However, I’ve run into another weirder thing:

When I run the file manually in ssh terminal, $NEWCHECK shows the file as OLD in the log - which makes sense. When run in cron, $NEWCHECK shows as NEW, even though the log entrees clearly show the date from oldmod.txt and oldhash.txt are the same as prior.

Cron was set to run every other minute for this example.
In the below code, you can see various ‘NEW’ and ‘OLD’ items. NEW are all from cron and always end with a timestamp seconds reading of ‘-01’. The OLD items were run manually, as shown by not ending in ‘-01’. Hashes and dates are identical to those found from more old*.txt and identical in the log, so it can’t be a case of cron changing the wget timestamping. I’m at a loss for why it’s always NEW.

By the way, I get identical results with NEW/OLD whether or not I create explicit paths to the files. ($LPATH/oldhash.txt, $LPATH/oldmod.txt, $LPATH/mod.log.txt, etc.)

I also confirmed that the files have the same hash and mod date by modifying the script not to remove the ‘wgotten’ files and then also adding a timestamp to the name on download. ( $ wget -O $MYSTAMP.testfile_10MB http://domain/files/tmp/testfile_10MB )
File hash and timestamp are properly preserved regardless of local rename upon acquisition.

It’s a puzzler. I’d be grateful for assistance.

$ more mod.log.txt 2012-06-12.15-23-01 - NEW - 2012-06-12 - f1c9645dbc14efddc7d8a322685f26eb 2012-06-12.15-25-01 - NEW - 2012-06-12 - f1c9645dbc14efddc7d8a322685f26eb 2012-06-12.15-26-07 - OLD - 2012-06-12 - f1c9645dbc14efddc7d8a322685f26eb 2012-06-12.15-27-01 - NEW - 2012-06-12 - f1c9645dbc14efddc7d8a322685f26eb 2012-06-12.15-39-45 - OLD - 2012-06-12 - f1c9645dbc14efddc7d8a322685f26eb 2012-06-12.15-41-01 - NEW - 2012-06-12 - f1c9645dbc14efddc7d8a322685f26eb 2012-06-12.15-43-01 - NEW - 2012-06-12 - f1c9645dbc14efddc7d8a322685f26eb 2012-06-12.15-45-01 - NEW - 2012-06-12 - f1c9645dbc14efddc7d8a322685f26eb $ more old*.txt :::::::::::::: oldhash.txt :::::::::::::: f1c9645dbc14efddc7d8a322685f26eb :::::::::::::: oldmod.txt :::::::::::::: 2012-06-12 $


#4

The cause is the same issue - there is an environment variable missing when cron is run.

It doesn’t make sense to use an interactive screen program to load values from text files in a non-interactive, non-screen process. Just sayin’


#5

[quote=“Atropos7, post:4, topic:57795”]
The cause is the same issue - there is an environment variable missing when cron is run.

It doesn’t make sense to use an interactive screen program to load values from text files in a non-interactive, non-screen process. Just sayin’
[/quote]Atropos7 - thanks again for your reply.

Thanks for your patience.
Just to be sure I understand what you’re referring to:
[list]
[]‘an interactive screen program’ refers to using MYVARIALBE=$([color=#FF0000]more[/color] myfile.txt) to load a variable, correct?
[
]‘non-interactive, non-screen process’ refers to the entire bash script ‘[color=#FF0000]verifyfile.sh[/color]’, also correct?
[/list]
There are so many ways of doing things in bash, and I’m most certainly by some standards a rank beginner. Some of the ways I do things are probably bass-ackwards, to be sure.

Not that I’m asking you to write it for me - but what methods would you find more reliable/useful/appropriate for keeping a couple variables between cron runs? or more over-arching, creating an autonotify script?


#6

Hmm… :slight_smile: I think I figured it out. I should use ‘cat’ instead of ‘more’. I also consolidated the variables to a single file. Is this closer to what you had in mind?

This works with cron:

[code]#!/bin/bash

file: verifychange.sh - an autonotfier script

LPATH="/home/username/verifyfiles"

Create my variables here at /home/username/verifyfiles/

MYSTAMP=$(date +%Y-%m-%d.%H-%M-%S)

Make sure $PATH/oldvars.txt exists and has variables in your implementation…

OLDMODDATE=$( cat $LPATH/oldvars.txt | awk ‘{ print $1 }’ )
OLDHASH=$( cat $LPATH/oldvars.txt | awk ‘{ print $2 }’ )

Get the latest file for verification.

wget -O $LPATH/$MYSTAMP.testfile_10MB http://externaldomain.com/sites/default/files/tmp/testfile_10MB
NEWHASH=$( md5sum $LPATH/$MYSTAMP.testfile_10MB | awk ‘{ print $1 }’ )
NEWMODDATE=$( stat -c %y $LPATH/$MYSTAMP.testfile_10MB | awk ‘{ print $1 }’ )
if [ “$NEWMODDATE” = “$OLDMODDATE” -a “$OLDHASH” = “$NEWHASH” ]
then
NEWCHECK="OLD"
echo "No change in file."
else
NEWCHECK="NEW"
echo “$NEWMODDATE $NEWHASH” > $LPATH/oldvars.txt
echo “File has changed.”
# Send static notification email via external php script.
# Since we’ve declared PATH, we can call php without the fuss.
# php /home/username/usr/local/scripts/notification-email.php
fi

Log entry.

echo “$MYSTAMP - $NEWCHECK - $NEWMODDATE - $NEWHASH” >> $LPATH/mod.log.txt
rm $LPATH/$MYSTAMP.testfile_10MB

Done.[/code]