/modules/simpleroute-1.2/helpers/simplerouter.php
https://github.com/robertleeplummerjr/bluebox · PHP · 360 lines · 226 code · 73 blank · 61 comment · 30 complexity · 515e711cb045189214dcfb76179193fa MD5 · raw file
- <?php defined('SYSPATH') or die('No direct access allowed.');
- /**
- * @package Simpleroute
- * @author K Anderson <bitbashing@gmail.com>
- * @license Mozilla Public License (MPL)
- */
- class simplerouter
- {
- public static function getOutboundPattern($simple_route_id, $engine = 'freeswitch')
- {
- $simpleRoute = Doctrine::getTable('SimpleRoute')->find($simple_route_id);
- if (empty($simpleRoute['patterns']))
- {
- return array();
- }
- // get the outbound patterns out of the record
- $patterns = $simpleRoute['patterns'];
- switch($simpleRoute['type'])
- {
- case SimpleRoute::TYPE_REGEX:
- $convert = FALSE;
- break;
-
- case SimpleRoute::TYPE_SIMPLE:
- default:
- $convert = TRUE;
- }
- $patterns = $simpleRoute['patterns'];
- // based on the requesting engine generate the pattern required
- switch(strtolower($engine))
- {
- case 'freeswitch':
- // Loop each rule and build a regex
- $pattern = Array();
- foreach ($patterns as $rule)
- {
- if (!$convert)
- {
- array_push($pattern, $rule);
- continue;
- }
- if (preg_match('/^[0-9]*$/', $rule))
- {
- if (preg_match('/\(/',$rule))
- {
- array_push($pattern, '^' . $rule . '$');
- }
- else
- {
- array_push($pattern, '^(' . $rule . ')$');
- }
- continue;
- }
- $rule = self::npaToRegex($rule);
- if (empty($rule))
- {
- continue;
- }
-
- // Convert the short hand into regex
- if (preg_match('/\(/',$rule))
- {
- array_push($pattern, '^' . $rule . '$');
- }
- else
- {
- array_push($pattern, '^(' . $rule . ')$');
- }
- }
- // we added a pipe on the end of every rule so remove the last one
- //$pattern = str_replace(array('{', '}'), array('\{', '\}'), $pattern);
- return $pattern;
-
- case 'asterisk':
- // Loop each rule and build a regex
- $pattern = array();
- foreach ($patterns as $rule)
- {
- if (!$convert)
- {
- $pattern .= $rule .'|';
- continue;
- }
-
- if (preg_match('/^[0-9]*$/', $rule))
- {
- $pattern .= '^' . $rule . '$|';
- continue;
- }
-
- $rule = self::npaToAsteriskShort($rule);
- if (empty($rule))
- {
- continue;
- }
-
- // Convert the short hand into regex
- $pattern += $rule;
- }
- // because of the asterisk restrictions we return an array of
- // patterns that make up the regex groups in freeswitch
- return $pattern;
-
- default:
- return FALSE;
- }
- }
- public static function npaToAsteriskShort($pattern = NULL)
- {
- if (empty($pattern))
- {
- return FALSE;
- }
- $pattern = str_replace(array('A', 'P', ' '), array('X', '[0-8]', ''), $pattern);
- // This is nasty but asterisk does not support a conditional match....
- // ...TO THE PERMUTATION ENGINE!
- $permutations = self::conditionPermutations($pattern);
- // Break the permutations into an array of patterns
- $patterns = explode('|', $permutations);
- // for each pattern we need two parts in asterisk, one that matches the
- // dialed number, and one to get the requested parts out of the number
- $results = array();
- foreach($patterns as $pattern)
- {
- // for the pattern used by asterisk remove the parentheses
- $cleanPattern = str_replace(array('(', ')'), array('', ''), $pattern);
- // if the pattern is just numbers then let asterisk handle it as
- // an extension
- if (!preg_match('/^[0-9]*$/', $cleanPattern))
- {
- $cleanPattern = '_' .$cleanPattern;
- }
- // for the actually outbound dial we need a rule about which
- // numbers to use from the pattern
- $exten = '${EXTEN';
- // we dont care about parentheses on the far left or right (IE: full
- // number or rest of number)
- $pattern = trim($pattern, '()');
- // find the first occurance of ( and if there that is our offset
- if ($pos = strpos($pattern, '('))
- {
- $exten .= ':' .$pos;
- }
- // find the last occurance of ) and if there that is our length
- if ($pos = strrpos($pattern, ')'))
- {
- $exten .= ':' .$pos;
- }
- // close this up
- $exten .= '}';
- // this array is key => value where key is the pattern necessary to
- // enter the dialplan and the value is a ${EXEN} construct with the
- // necessary offset and length
- $results[$cleanPattern] = $exten;
- }
-
- return $results;
- }
- // This is a recursive function that will return a list of all possible
- // permutaions around the conditional match ? token
- public static function conditionPermutations($pattern)
- {
- if ($pos = strpos($pattern, '?'))
- {
- $patternWith = substr($pattern, 0, $pos) .substr($pattern, $pos+1);
- $patternWithOut = substr($pattern, 0, $pos-1) .substr($pattern, $pos+1);
- return self::conditionPermutations($patternWith) .'|' .self::conditionPermutations($patternWithOut);
- }
- else
- {
- return $pattern;
- }
- }
- public static function npaToRegex($pattern = NULL)
- {
- if (empty($pattern))
- {
- return FALSE;
- }
- // split the npa into an pattern
- $pattern = str_split($pattern);
- $iteration = 1;
- $prevRule = '';
- foreach ($pattern as $key => $rule)
- {
- // remove spaces
- if ($rule == ' ')
- {
- unset($pattern[$key]);
-
- continue;
- }
- // if this is not escaped then replace the pattern
- if ($prevRule != '\\')
- {
- // find our pattern stand ends and replace them
- switch($rule)
- {
- case 'X':
- case 'A':
- $pattern[$key] = '[0-9]';
- break;
- case 'P':
- $pattern[$key] = '[0-8]';
- break;
- case 'Z':
- $pattern[$key] = '[1-9]';
- break;
- case 'N':
- $pattern[$key] = '[2-9]';
- break;
- case '!':
- $pattern[$key] = '.*';
- break;
- case '.':
- $pattern[$key] = '.+';
- break;
- case '?':
- $pattern[$key] = '{0,1}';
- break;
- }
- // update the rule so we process this correctly
- $rule = $pattern[$key];
- }
- else
- {
- // if the previous rule was an escape remove the marker
- unset($pattern[$key - 1]);
- }
- if ($rule == $prevRule)
- {
- // if the rule is the same as the last inc iteration of the rule
- unset($pattern[$key]);
- $iteration++;
- }
- else if ($iteration > 1)
- {
- // if we where tracking iterations and are at a new rule
- // then add in the iteration count are rest iteration
- //
- // if the next element is itself an iterator handle it diff
- if (in_array($rule, array('.*', '.+')))
- {
- // since the next rule is an iterator we need to put
- // back something for it to iterate against
- $iteration--;
- // if that action reduced us to one then we dont need
- // an iterator after all
- if ($iteration > 1)
- {
- $pattern[$key] = '{' . $iteration . '}'. $prevRule . $rule;
- }
- else
- {
- $pattern[$key] = $prevRule . $rule;
- }
- }
- else
- {
- // if this is a iterated element followed by a non iterator
- // print our iterator and the new rule, no need to
- // backtrack for a pattern
- $pattern[$key] = '{' . $iteration . '}'. $rule;
- }
- $prevRule = $rule;
- $iteration = 1;
- }
- else
- {
- // otherwise just track the rules
- $prevRule = $rule;
- }
- }
- // if we left the loop with a final iteration then add that
- if ($iteration > 1)
- {
- $pattern[] = '{' . $iteration . '}';
- }
- // make our pattern from the array parts
- $pattern = implode('', $pattern);
- // if there is no opening parentheses assume it
- // belongs on the front
- if (!strstr($pattern, '('))
- {
- $pattern = '(' . $pattern;
- }
- // if there is no closing parentheses assume it
- // belongs on the end
- if (!strstr($pattern, ')'))
- {
- $pattern .= ')';
- }
- // return out regex
- return $pattern;
- }
- }