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

в 17:27, , рубрики: asterisk, def-коды, ip-телефония, php, sip, метки: , , ,

Что имеем на входе:

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

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

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

Автор: RSM

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js