3 сентября 2012

Генератор масок из интервалов DEF кодов для Asterisk

PHPAsteriskРазработка систем связи
Что имеем на входе:
  1. несколько SIP операторов для исходящей связи, причём у некоторых более «вкусные» тарифы на определенного мобильного оператора;
  2. данные по DEF кодам на rossvyaz.ru выделенным операторам, но разбитыми на интервалы в том числе смежные (особенно заметно для МегаФона);
  3. настроенный Asterisk в виде дистрибутива Elastix.

На выходе хотим получить список масок для определения номеров московских сотовых операторов (МСС, Билайн, МТС, МегаФон). Для этого за пару часов был написан небольшой скрипт, который наверняка может пригодиться кому-то еще и при небольших изменениях может быть переделан под других операторов или другие регионы.

Upd.: генератор масок по DEF-кодам для Asterisk — теперь и онлайн =).

<?php
$linecode = '98'; // код для звонков на мобильные
// берем таблицу
$file = fopen('http://www.rossvyaz.ru/docs/articles/DEF-9x.html', 'r');
// получаем и разбираем таблицу
$defs = array();
while(($line = fgets($file)) && ($line !== FALSE)) {
    $line = iconv('WINDOWS-1251', 'UTF-8', $line);
    if(preg_match('|<tr>\s*<td>\s*(\d+)\s*</td>\s*<td>\s*(\d+)\s*</td>\s*<td>\s*(\d+)\s*</td>\s*<td>\s*(\d+)\s*</td>\s*<td>\s*(.+?)\s*</td>\s*<td>\s*(.+?)\s*</td>\s*</tr>|', $line, $matches)) {
        if(!isset($defs[$matches[6]])) {
            $defs[$matches[6]] = array();
        }
        if(!isset($defs[$matches[6]][$matches[5]])) {
            $defs[$matches[6]][$matches[5]] = array();
        }
        $defs[$matches[6]][$matches[5]][] = array($matches[1],$matches[2],$matches[3]);
    }
}
fclose($file);
// выбираем интересующие нас записи и объединяем смежные интервалы
$selected = array();
foreach($defs as $reg => $ops) {
    if($reg == 'Москва и Московская область') {
        foreach($ops as $op => $cs) {
            usort($cs, "cmp_defs");
            switch($op) {
                case 'Московская сотовая связь':
                case 'Вымпел-Коммуникации':
                case 'Мобильные ТелеСистемы':
                case 'МегаФон':
                    if(!isset($selected[$op])) {
                        $selected[$op] = array();
                    }
                    $newset = true; $cnt = 1;
                    foreach($cs as $cid => $c) {
                        if($newset) {
                            $selected[$op][] = array($c[0], $c[1]);
                        }
                        if(isset($cs[$cid+1]) && ($c[0] == $cs[$cid+1][0]) && (($c[2] + 1) == $cs[$cid+1][1])) {
                            $newset = false;
                            $cnt++;
                        } else {
                            $selected[$op][count($selected[$op]) - 1][2] = $c[2];
                            $newset = true;
                            $cnt = 1;
                        }
                    }
                    break;
            }
        }
    }
}
// генерируем маски для Asterisk
$regs = array();
foreach($selected as $op => $defs) {
    $regs[$op] = array();
    foreach($defs as $def) {
        // если кто будет разбираться, то здесь мозг отказал мне
        // $leq - это про правую часть, а $req про левую =)
        $pref = $def[0];
        $first = $def[1];
        $last = $def[2];
        if($first > $last) {
            $tmp = $first;
            $first = $last;
            $last = $tmp;
        }
        // маски разбиваем на три массива и вгоняем через unshift/push исключительно с целью удобства поиска ошибок =)
        $r = array();
        $rf = array();
        $rl = array();
        $req = 0;
        for($i = 0; $i < 7; $i++) {
            if($first[$i] === $last[$i]) {
                $req++;
            } else {
                break;
            }
        }
        $leq = 0;
        for($i = 6; $i >= 0; $i--) {
            if(($first[$i]) === "0" && ($last[$i] === "9")) {
                $leq++;
            } else {
                break;
            }
        }
        $zf = true;
        $nl = true;
        if($leq + $req < 6)
            for($i = $leq; $i + $req < 6; $i++) {
                $sl = 6 - $i;
                $pf = substr($first, 0, 6 - $i);
                $pl = substr($last, 0, 6 - $i);
                if($pf < $pl) {
                    $x = $first[6 - $i];
                    if(!$zf || ($x != '0')) {
                        switch($x) {
                            case '9':
                                array_push($rf, $pref . $pf . '9' . str_repeat('X', $i));
                                break;
                            case '8':
                                array_push($rf, $pref . $pf . '[89]' . str_repeat('X', $i));
                                break;
                            default:
                                array_push($rf, $pref . $pf . '[' . $x . '-9]' . str_repeat('X', $i));
                        }
                        $first = sprintf('%0' . $sl . 'd', substr($first, 0, $sl) + 1 ) . str_repeat('0', 7 - $sl);
                        $zf = false;
                    }
                    $x = $last[6 - $i];
                    if(!$nl || ($x != 9)) {
                        switch($x) {
                            case '0':
                                array_unshift($rl, $pref . $pl . '0' . str_repeat('X', $i));
                                break;
                            case '1':
                                array_unshift($rl, $pref . $pl . '[01]' . str_repeat('X', $i));
                                break;
                            default:
                                array_unshift($rl, $pref . $pl . '[0-' . $x . ']' . str_repeat('X', $i));
                        }
                        $last = sprintf('%0' . $sl . 'd', substr($last, 0, $sl) - 1 ) . str_repeat('9', 7 - $sl);
                        $nl = false;
                    }
                }
                $leq++;
            }
        if($leq + $req <= 7) {
            if($leq < 7) {
                $sl = 6 - $leq;
                $pf = substr($first, 0, 6 - $leq);
                $pl = substr($last, 0, 6 - $leq);
                $xf = $first[6 - $leq];
                $xl = $last[6 - $leq];
                if(($pf == $pl) && ($xf <= $xl)) {
                    if($xf == $xl) {
                        $r[] = $pref . $pf . $xf . str_repeat('X', $leq);
                    } elseif($xf + 1 == $xl) {
                        $r[] = $pref . $pf . '[' . $xf . $xl . ']' . str_repeat('X', $leq);
                    } else {
                        $r[] = $pref . $pf . '[' . $xf . '-' . $xl . ']' . str_repeat('X', $leq);
                    }
                }
            } else {
                $r[] = $pref . str_repeat('X', $leq);
            }
        }

        $regs[$op] = array_merge($regs[$op], $rf, $r, $rl);
    }
}
foreach($regs as $op => $reg) {
    echo "\n\n=== $op ===\n\n";
    foreach($reg as $r) {
        echo $linecode . $r . "\n";
    }
}

function cmp_defs($a, $b) {
    if($a[0] != $b[0])
        return $a[0] - $b[0];
    return $a[1] - $b[1];
}
?>

В настоящий момент получил следующий результат: из таблицы по состоянию на 01.09.2012.

P.S.: код жестоко привязан к выдаче Россвязи, так что начало интервала всегда оканчивается нулями, а конец — девятками. Это DEF-коды — так что семь цифр.
P.P.S.: на всякий случай уточню — да, это не самый красивый код, но когда нужен вспомогательный скрипт — то можно и так =)
Теги:PHPAsteriskDEF-кодысокращение расходовSIP
Хабы: PHP Asterisk Разработка систем связи
+6
9,1k 42
Комментарии 9
Похожие публикации
системный администратор, администратор сети ПД
от 60 000 до 120 000 ₽Первый ТелекомМосква
Senior Backend developer (remote)
до 3 500 $Stark GamesМинскМожно удаленно
Product Manager | Mobile (Мобильная разработка)
от 70 000 ₽asteroidСанкт-Петербург
PHP developer
до 250 000 ₽РНКБ Банк (ПАО)МоскваМожно удаленно
PHP-разработчик
от 40 000 до 60 000 ₽Dota2.ruМожно удаленно
Лучшие публикации за сутки