Как стать автором
Обновить

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

Время на прочтение3 мин
Количество просмотров9.6K
Что имеем на входе:
  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.: на всякий случай уточню — да, это не самый красивый код, но когда нужен вспомогательный скрипт — то можно и так =)
Теги:
Хабы:
Всего голосов 8: ↑7 и ↓1+6
Комментарии9

Публикации

Истории

Работа

PHP программист
122 вакансии

Ближайшие события

27 августа – 7 октября
Премия digital-кейсов «Проксима»
МоскваОнлайн
19 сентября
CDI Conf 2024
Москва
20 – 22 сентября
BCI Hack Moscow
Москва
24 сентября
Конференция Fin.Bot 2024
МоскваОнлайн
25 сентября
Конференция Yandex Scale 2024
МоскваОнлайн
28 – 29 сентября
Конференция E-CODE
МоскваОнлайн
28 сентября – 5 октября
О! Хакатон
Онлайн
30 сентября – 1 октября
Конференция фронтенд-разработчиков FrontendConf 2024
МоскваОнлайн
3 – 18 октября
Kokoc Hackathon 2024
Онлайн