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

    Что имеем на входе:
    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.: на всякий случай уточню — да, это не самый красивый код, но когда нужен вспомогательный скрипт — то можно и так =)

    Similar posts

    Ads
    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More

    Comments 9

      0
      В таблице DEF-кодов МТС может обозначаться еще и как «МобильныеТелеСистемы».
        0
        У них всё там сильно запущено, но в московском регионе они исключительно с одним пробелом в текущей таблице. Возможно пробелами Россвязь разделяет разные юр.лица с общим названием. Видели бы вы какое количество пробелов может быть у разных ООО «Вектор» на ЭТП zakazrf.ru — где название должно быть уникальным (вот уж извратились =), а всяких одноименных ООО «Вектор» хоть пруд пруди.
        0
        FastAGI + DB ИМХО будет быстрее и меньше жрать ресурсов…
          0
          Все зависит от условий и целей. Мне это нужно было для офиса с 60 абонентами — там Elastix крутится на виртуалке с одним ядром и 256Мб ОЗУ и даже при таком числе ресурсов загрузка минимальна — так что о скорости и ресурсах в моем случае речь не идет. Как еще не маловажный плюс — Elastix без самописных FastAGI скриптов я спокойно передал своему «наследнику» при смене работы и не волнуюсь что у него возникнут проблемы с поддержкой или периодическим (раз в пару месяцев) обновлением 3-х правил для операторов.
            0
            ну на 60 абонентов — да, у меня порядка 1к и разные тарифы по направлениям — там FastAGI лучше справляется
              0
              При решении задачи всегда следует учитывать всё с ней связанное, а то в моем случае FastCGI — это как из пушки по воробьям, ну а в вашем вполне вероятны дикие тормоза при простом перечислении правил. =)
          0
          Сдох сайт?)

        Only users with full accounts can post comments. Log in, please.