I found a bug in my PHP code that caused strings to match when parsing the AutoResponder config file for responses to submitted text messages. I was using old DOS style wildcards * and ? to make it easy to write the config file. But my comparison functions were just long and complicated and screwed up.

The solution to the problem was to switch to using regular expressions. But those asterisks are so handy for their simplicity. Here are some XML elements from the config file that are used for matching an incoming message with an appropriate response:

<response keyword="* hint *" answer="1">Hint 1</response>
<response keyword="help *">Your message […]</response>
<response keyword="register * team *" answer="#" action="register"></response>

The new code let’s me use multiple asterisks in the keyword attributes but only allows one of them to have data. So if someone sends a text message “hint1”, it will match that first XML element because only one asterisk represents data and whitespace is ignored (I hope ignoring it is a good choice for my application).

I will explain the CompareNumberString() function is in a moment. The WildCardStringMatch() function runs first and converts a keyword string from the config file with asterisks to a regular expression. Then it just compares/processes the regular expression with the input string. If there is data that matches one of those asterisks, a second comparison is done to see if that data matches the answer attribute. In the case of our “hint1” input, it matches because the “1” matches the “1” in the answer attribute. If the input had been “hint2”, it would not have matched and the code would look for some other match from a different response element. “1 hint” would also match but “1 hint 1” would not match because only one asterisk is allowed to have matching data.

The “help” XML element up there doesn’t care what message is sent, it accepts anything and some other PHP code handles getting help for the sender.

The last XML element up there in the sample config data has a hash tag (“pound sign” or “number sign” if you are more than 20 years old) in the answer attribute. Whenever an asterisk matches some data, the resulting data is then compared to the answer attribute. If there is no answer attribute, it is just considered a match. But when the answer has the hash tag, this is where the CompareNumberString() function is called. The CompareNumberString() function compares the input string to the answer attribute seeing if it is a number and if it matches an optional range of values in the answer attribute that are acceptable. Matching a range of values lets the config file specify how to handle numbers that are too large or too small.

This code is working much better than my previous version and is much more flexible.