Pull to refresh

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

Reading time3 min
Views9.7K
Что имеем на входе:
  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.: на всякий случай уточню — да, это не самый красивый код, но когда нужен вспомогательный скрипт — то можно и так =)
Tags:
Hubs:
Total votes 8: ↑7 and ↓1+6
Comments9

Articles