I wanted to add notification functionalities to Kyusl.com, so that I could be informed about certain events, but at the same time there will be a limit on how many notifications will I get on a given day. My cell phone plan at German Vodafone comes with an E-mail account, and every time I get an E-mail, Vodafone sends me an SMS that includes the subject of the E-mail. To read the message, you have to have an appropriate cell phone, but for short notifications you can pack most important things right into the subject line. That allows me to get the most important information for free almost anywhere in the world, which is important if I go on vacation (normally, SMS roaming doesn’t cost anything).
I called the concept “counted events”. One of the “events” would happen when someone uses the contact form, which sends a message (not E-mail!) to the administrative user. If that happens, I want to inform myself about that, but not more often than two times per day. Then I can login into Kyusl and check the message.
I have decided to keep the track of one “counted event” in one database record per user. Obviously, you have to reasonably limit the number of events per given period if you don’t want to have several records per event. I allow maximum five events per period, here’s MySQL declaration:
create table ceventlog (
uid integer,
cevent varchar(8) not null,
alimit integer,
period integer,
t1 integer,
t2 integer,
t3 integer,
t4 integer,
t5 integer,
primary key ceventlog_key (uid,cevent)
);
Period field measures the period in seconds, and t1 to t5 represent a rolling log of timestamps telling when has the event happened. Every time the event happens, I shift the values “down” and write the current UNIX timestamp into t1. Then if, say, I want to check whether I have reached four events in the given period, I check the time difference between now and t4, whether it exceeds the time limit in the “period” field.
Two functions can either init an event or reset it. First I had a reset in the init function (to count for the case when calling insert on existing record), but then decided that if I don’t reset the event in the init, I can safely call the init every time without zapping the log:
function InitCEvent($uid, $cevent, $limit, $period) {
$query = "insert into ceventlog (uid,cevent,alimit,period,t1,t2,t3,t4,t5)".
" values ($uid,'$cevent',$limit,$period,0,0,0,0,0)";
$result = mysql_query($query);
// if we don't call Reset - insert will fail if the record exists,
// so Init can be called every time, and Reset can be called on demand.
// ResetCEvent($uid, $cevent); // just in case we had a record already
}
function ResetCEvent($uid, $cevent) {
$query = "update ceventlog set t1=0 t2=0 t3=0 t4=0 t5=0".
" where uid=$uid and cevent='$cevent'";
$result = mysql_query($query);
}
When the event happens, I shift the values in the event log with the following function:
function ShiftCEvent($uid, $cevent) {
$query = "select alimit,t1,t2,t3,t4,t5 from ceventlog".
" where uid=$uid and cevent='$cevent'";
$result = mysql_query($query);
if (!$result) {
return 0;
}
else {
$num_rows = mysql_num_rows($result);
if( $num_rows == 0 ) {
return 0;
}
else {
$row = mysql_fetch_row($result);
list($limit,$t1,$t2,$t3,$t4,$t5) = $row;
$t5 = $t4;
$t4 = $t3;
$t3 = $t2;
$t2 = $t1;
$t1 = time();
$query = "update ceventlog set t1=$t1, t2=$t2, t3=$t3, t4=$t4, t5=$t5".
" where uid=$uid and cevent='$cevent'";
$result = mysql_query($query);
}
}
}
And finally, to check whether the limit is reached, I have this:
function CEventLimitReached($uid, $cevent) {
$query = "select alimit,period,t1,t2,t3,t4,t5 from ceventlog".
" where uid=$uid and cevent='$cevent'";
$result = mysql_query($query);
if (!$result) {
return 0;
}
else {
$num_rows = mysql_num_rows($result);
if( $num_rows == 0 ) {
return 0;
}
else {
$row = mysql_fetch_row($result);
list($limit,$period,$t1,$t2,$t3,$t4,$t5) = $row;
$now = time();
if( $limit == 1 ) {
if( $t1 == 0 || $now - $t1 > $period ) return 0;
else return 1;
}
elseif( $limit == 2 ) {
if( $t2 == 0 || $now - $t2 > $period ) return 0;
else return 1;
}
elseif( $limit == 3 ) {
if( $t3 == 0 || $now - $t3 > $period ) return 0;
else return 1;
}
elseif( $limit == 4 ) {
if( $t4 == 0 || $now - $t4 > $period ) return 0;
else return 1;
}
elseif( $limit == 5 ) {
if( $t5 == 0 || $now - $t5 > $period ) return 0;
else return 1;
}
}
}
}
For each event, I have written a corresponding notification function. For notifications about admin messages mentioned above, I have the code similar to:
function AdminMessageNotify() {
InitCEvent(1,'ADM_MSG',2,3600*24);
if( !CEventLimitReached(1,'ADM_MSG') ) {
$message = 'New message to admin!';
$email = 'my_email_id_at@vodafone.de';
$send = @mail("$email", "New adm msg", $message,
"From: myuser@mydomain.com\\r\\n"
."Reply-To: myuser@mydomain.com\\r\\n" );
}
ShiftCEvent(1,'ADM_MSG');
}
The code in the contact.php, after sending a message to administrator, is simply the call of AdminMessageNotify.
That simple set of functions can be used easily to notify webmasters about data processing errors (database, for example), traffic and many others that may require webmaster’s attention. I will greatly appreciate any improvement ideas you may want to share.