- PVSM.RU - https://www.pvsm.ru -

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

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

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

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

<?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 [4].

P.S.: код жестоко привязан к выдаче Россвязи, так что начало интервала всегда оканчивается нулями, а конец — девятками. Это DEF-коды — так что семь цифр.
P.P.S.: на всякий случай уточню — да, это не самый красивый код, но когда нужен вспомогательный скрипт — то можно и так =)

Автор: RSM


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/php-2/14376

Ссылки в тексте:

[1] rossvyaz.ru: http://www.rossvyaz.ru/docs/articles/DEF-9x.html

[2] Asterisk: http://www.asterisk.org

[3] Elastix: http://www.elastix.org

[4] из таблицы по состоянию на 01.09.2012: http://pastebin.com/xAwdv118