A text conversation went viral a while ago, where a guy sent his friend text messages about cat facts, and then messed with him when he tried to get them to stop. It was a clever idea, and seemed like a quick app to make using Twilio, so I did.

The initial system was made in about 20 minutes, but I kept adding features and fixes. You send the phone number you would like to annoy to your Twilio number, then the system will send a cat fact to your friend. Messages that do not contain a phone number will be responded with more cat facts. Here's how it looks now:

[php title="sms.php"]
<?php
$AccountSid = "ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
$Authtoken = "YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY";
// Get a greeting based on the body
$Body = $_GET['Body'];
if(stripos($Body, "e4n3m23pd90vc4:9nfaDFADFD42baconP0o") !== FALSE){
$greeting = "&lt;Command not recognized&gt; ";
}
else if(stripos($Body, "stop") !== FALSE || strlen($Body)>30){
$greeting = "Hammer time. ";
}
else if(stripos($Body, "fuck") !== FALSE || stripos($Body, "shit") !== FALSE || stripos($Body, "asshole") !== FALSE){
$greeting = "Watch your language meow! ";
}
else{
$greeting = "Thank you for using Fun Feline Facts! ";
}

// Keep from infinite loops
if(phoneUs($Body)==phoneUs($_GET['To'])){
return;
}

// Stop abusers
$url = "https://$AccountSid:$Authtoken@api.twilio.com/2010-04-01/Accounts/$AccountSid/SMS/Messages.json?To=". $_GET['To'] . "&From=" . $_GET['From'] . "&DateSent=" . date("Y-m-d");
$result = json_decode(getUrl($url), true);
$count = (isset($result['total'])) ? $result['total'] : 0;

// Load the file
$handle = fopen("facts.txt", 'r');
$facts = array();
while($fact = fgets($handle))
array_push($facts, $fact);

$message = "";
while($message=="" || strlen($message)>160){
$random = rand(0, count($facts));
$randomFact = trim($facts[$random]);

$message = htmlspecialchars("$greeting$randomFact Me-wow!");
}

$toAttribute = (phoneUs($Body)!=0) ? "to="" . phoneUs($Body) . """ : "";
echo "<?xml version="1.0" encoding="UTF-8"?>";
echo "<Response>";
if($count<8){
while(strlen($message)>0){
echo "<Sms $toAttribute>" . substr($message, 0, 160) . "</Sms>";
$message = substr($message, 160);
}
if($toAttribute != "" && phoneUS($Body) != phoneUs($_GET['From']))
echo "<Sms>(" . ++$count . " of 8 per day)A cat fact has been sent to your friend. Purr-fect! felinefacts@bold-it.com</Sms>";
}
echo "</Response>";

function phoneUS($number){
$pattern = "/^D*[1]?D*(d{3})D*(d{3})D*(d{4})(?:D*[xX]D*(d*))?$/";
preg_match($pattern, $number, $numberArray);

if(!$numberArray){
return 0;
}
$extension = isset($numberArray[4]) ? $numberArray[4] : "";
return "+1".$numberArray[1].$numberArray[2].$numberArray[3];
}

function getUrl($url) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$result = curl_exec($ch);
curl_close($ch);
return $result;
}
?>
[/php]

And the file of facts it uses

The first section (lines 6-17) add a little spice to the conversation. If it detects a few key words, it will change the message slightly.

[php]
// Get a greeting based on the body
if(stripos($Body, "e4n3m23pd90vc4:9nfaDFADFD42baconP0o") !== FALSE){
$greeting = "&lt;Command not recognized&gt; ";
}
else if(stripos($Body, "stop") !== FALSE || strlen($Body)>30){
$greeting = "Hammer time. ";
}
else if(stripos($Body, "fuck") !== FALSE || stripos($Body, "shit") !== FALSE || stripos($Body, "asshole") !== FALSE){
$greeting = "Watch your language meow! ";
}
else{
$greeting = "Thank you for using Fun Feline Facts! ";
}
[/php]

Someone had the bright idea to send its own number to itself, causing an infinite loop. After it crashed the system, I put the next section in.

[php]// Keep from infinite loops
if(phoneUs($Body)==phoneUs($_GET['To'])){
return;
}[/php]

We got a few people who would spam the same number 30+ times, really racking up the credit costs. To stop this, I checked the logs to see how often they had used the system that day, and stopped working at around 8 messages.

[php]// Stop abusers
$url = "https://$AccountSid:$Authtoken@api.twilio.com/2010-04-01/Accounts/$AccountSid/SMS/Messages.json?To=". $_GET['To'] . "&From=" . $_GET['From'] . "&DateSent=" . date("Y-m-d");
$result = json_decode(getUrl($url), true);
$count = (isset($result['total'])) ? $result['total'] : 0;[/php]

After those checks, it loads the cat fact file, picks one (that will fit in just one message), and puts the greeting, fact and suffix together.

[php]// Load the file
$handle = fopen("facts.txt", 'r');
$facts = array();
while($fact = fgets($handle))
array_push($facts, $fact);

$message = "";
while($message=="" || strlen($message)>160){
$random = rand(0, count($facts));
$randomFact = trim($facts[$random]);

$message = htmlspecialchars("$greeting$randomFact Me-wow!");
}[/php]

Lastly, it prepares a TwiML response, directing one message to the new person, and one back at the sender as confirmation.

[php]$toAttribute = (phoneUs($Body)!=0) ? "to="" . phoneUs($Body) . """ : "";
echo "<?xml version="1.0" encoding="UTF-8"?>";
echo "<Response>";
if($count<8){
while(strlen($message)>0){
echo "<Sms $toAttribute>" . substr($message, 0, 160) . "</Sms>";
$message = substr($message, 160);
}
if($toAttribute != "" && phoneUS($Body) != phoneUs($_GET['From']))
echo "<Sms>(" . ++$count . " of 8 per day)A cat fact has been sent to your friend. Purr-fect! felinefacts@bold-it.com</Sms>";
}
echo "</Response>";[/php]

At the end of my file I've made two helper functions. The first takes the body of the text message and sees if it can pull a US phone number from it (since people have many ways of creating a phone number) and returns it in standard format. The second function is just a cURL function that helps handling the call to the Twilio SMS Log.

[php]function phoneUS($number){
$pattern = "/^D*[1]?D*(d{3})D*(d{3})D*(d{4})(?:D*[xX]D*(d*))?$/";
preg_match($pattern, $number, $numberArray);

if(!$numberArray){
return 0;
}
$extension = isset($numberArray[4]) ? $numberArray[4] : "";
return "+1".$numberArray[1].$numberArray[2].$numberArray[3];
}

function getUrl($url) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$result = curl_exec($ch);
curl_close($ch);
return $result;
}[/php]