Вер 062013
 

 

Каталог GSM шлюзов для Asterisk от производителя Dinstar, с их расшифровкой

Dinstar – один из крупнейших производителей VoIP/GSM шлюзов, аналоговых шлюзов доступа, а также цифровых VoIP шлюз с Е1 потоками. VoIP/GSM шлюзы серии DWG2000 – это многофункциональные устройства, применяемые для соединения GSM и VoIP сетей. Серия шлюзов DWG2000 используется для связи с офисной АТС, в качестве резервного канала для PSTN и обеспечивает функцию LCR (маршрутизация по критерию наименьшей стоимости) для центра обработки вызовов.

Многокональные GSM, GSM/VoIP, SMS шлюзы

Настольный вариант:

Dinstar DWG2000-1G ( 1 GSM, WAN, LAN, G.711, G.723.1, G.729A)

Dinstar DWG2000С-4G ( 4 GSM, WAN, LAN, G.711, G.723.1, G.729A, поддержка SIM Bank)

Dinstar DWG2000СSE-4G Call Center Edition ( 4 GSM, WAN, LAN, G.711, G.723.1, G.729A, поддержка SIM Bank, special firware and hardware design)

Dinstar DWG2000C-8G ( 8 GSM, WAN, LAN, G.711, G.723.1, G.729A, поддержка SIM Bank )

Dinstar DWG2000CSE-8G Call Center Edition ( 8 GSM, WAN, LAN, G.711, G.723.1, G.729A, поддержка SIM Bank, special firmware and hardware design)

Для стоек:

1U Rack Mount

Dinstar DWG2000B-8G (1U Rack, 8 GSM, WAN, LAN, G.711, G.723.1, G.729A, поддержка SIM Bank, расширение до 16 GSM)

Dinstar DWG2000BSE-8G Call Center Edition (1U Rack, 8 GSM, WAN, LAN, G.711, G.723.1, G.729A, поддержка SIM Bank, расширение до 16 GSM, special firware and hardware design)

Dinstar DWG2000B-16G (1U Rack, 16 GSM, WAN, LAN, G.711, G.723.1, G.729A, поддержка SIM Bank )

Dinstar DWG2000BSE-16G Call Center Edition (1U Rack, 16 GSM, WAN, LAN, G.711, G.723.1, G.729A, поддержка SIM Bank, special firware and hardware design)

2U Rack Mount

Dinstar DWG2000D-8G (2U Rack, 8 GSM, WAN, LAN, G.711, G.723.1, G.729A, поддержка SIM Bank, расширение до 32 GSM )

Dinstar DWG2000DSE-8G Call Center Edition (2U Rack, 8 GSM, WAN, LAN, G.711, G.723.1, G.729A, поддержка SIM Bank, расширение до 32 GSM, special firmware and hardware design)

Dinstar DWG2000D-16G (2U Rack, 16 GSM, WAN, LAN, G.711, G.723.1, G.729A, поддержка SIM Bank. расширение до 32 GSM )

Dinstar DWG2000DSE-16G Call Center Edition (2U Rack, 16 GSM, WAN, LAN, G.711, G.723.1, G.729A, поддержка SIM Bank. расширение до 32 GSM, special firmware and hardware design)

Dinstar DWG2000D-24G (2U Rack, 24 GSM, WAN, LAN, G.711, G.723.1, G.729A, поддержка SIM Bank, расширение до 32 GSM)

Dinstar DWG2000DSE-24G Call Center Edition (2U Rack, 24 GSM, WAN, LAN, G.711, G.723.1, G.729A, поддержка SIM Bank, расширение до 32 GSM, special firmware and hardware design)

Dinstar DWG2000D-32G (2U Rack, 32 GSM, WAN, LAN, G.711, G.723.1, G.729A, поддержка SIM Bank )

Dinstar DWG2000DSE-32G Call Center Edition (2U Rack, 32 GSM, WAN, LAN, G.711, G.723.1, G.729A, поддержка SIM Bank, special firmware and hardware design )

Карта на 8 GSM каналов для (1U Rack и 2U Rack Mount)

SIM BANK

Dinstar SimBank 32 (32 Sim card slot, remote, powerful sim manage, support share multi DWG)

Dinstar SimBank 64 (64 Sim card slot, remote, powerful sim manage, support share multi DWG)

Dinstar SimBank 128 (128 Sim card slot, remote, powerful sim manage, support share multi DWG)

SIM SERVER

Dinstar Sim Server with Public Cloud (Базовые функции)

Dinstar Sim Server with Public Cloud (Спеиальные функции, расширенный функционал, оплата за 1 Sim карту в месяц)

Dinstar SIM Server with Customer Local Server (first package pricing) (Базовые функции)

Dinstar SIM Server with Customer Local Server (first package pricing) (Спеиальные функции, расширенный функционал, за 256 Sim карт в год)

Dinstar SIM Server with Customer Local Server (first package pricing) (Спеиальные функции, расширенный функционал, за 512 Sim карт в год)

Dinstar SIM Server with Customer Local Server (second package pricing) (Спеиальные функции, расширенный функционал, за 128 Sim карт на следующие года)

Аксессуары

32 Converter

ПО для рассылки SMS и мониторинг USSD

Многокональные CDMA/VoIP шлюзы (800 MHz)

1U Rack Mount

Dinstar DWG2000B-8C (1U Rack, 8 CDMA, WAN, LAN, G.711, G.723.1, G.729A, расширение до 16 CDMA)

Dinstar DWG2000B-16C (1U Rack, 16 CDMA, WAN, LAN, G.711, G.723.1, G.729A)

Dinstar DWG2000D-8C (2U Rack, 8 CDMA, WAN, LAN, G.711, G.723.1, G.729A, расширение до 32 CDMA )

Dinstar DWG2000D-32C (2U Rack, 16 CDMA, WAN, LAN, G.711, G.723.1, G.729A, )

Карта на 8 CDMA каналов для (1U Rack и 2U Rack Mount)

Многокональные IP шлюзы

Dinstar DAG1000-4S (4 FXS, WAN, LAN, T.38 Fax, G.711, G.723.1, G.729A)

Dinstar DAG1000-4O (4 FXO, WAN, LAN, T.38 Fax, G.711, G.723.1, G.729A)

Dinstar DAG1000-4S4O (4 FXS, 4 FXO, WAN, LAN, T.38, Fax G.711, G.723.1, G.729A)

Dinstar DAG1000-8S (8 FXS, WAN, LAN, T.38 Fax, G.711, G.723.1, G.729A)

Dinstar DAG1000-8O (8 FXO, WAN, LAN, T.38 Fax, G.711, G.723.1, G.729A)

Dinstar DAG2000-16S (16 FXS, WAN, LAN, T.38 Fax, G.711, G.723.1, G.729A) $516 Новинка

Dinstar DAG2000-16O ( 16 FXO, WAN, LAN, T.38 Fax, G.711, G.723.1, G.729A) $638 Новинка

Dinstar DAG2000-8S8O ( 8 FXS, 8 FXO, WAN, LAN, T.38, Fax G.711, G.723.1, G.729A)

Dinstar DAG2000-24S ( 24 FXS, WAN, LAN, T.38 Fax, G.711, G.723.1, G.729A) $852 Новинка

Dinstar DAG2000-32S ( 32 FXS, WAN, LAN, T.38 Fax, G.711, G.723.1, G.729A)

Многокональные E1/T1 шлюзы

Dinstar MTG200-1*E1 (1*E1/T1, SIP, PRI)

Dinstar MTG200-2*E1 (2*E1/T1, SIP, PRI)

Dinstar MTG200-4*E1 (4*E1/T1, SIP, PRI)

Для стойки 1U
Dinstar MTG1000B-1*E1 (1E1/T1, 2 10/100MBase-T, 1 RS232 Console, SIP1.0/2.0, PRI, SS7 TUP/ISUP protocol)

Dinstar MTG1000B-2*E1 (2E1/T1, 2 10/100MBase-T, 1 RS232 Console, SIP1.0/2.0, PRI, SS7 TUP/ISUP protocol)

Dinstar MTG1000B-4*E1 (4E1/T1, 2 10/100MBase-T, 1 RS232 Console, SIP1.0/2.0, PRI, SS7 TUP/ISUP protocol)

Dinstar MTG1000B-8*E1 (8E1/T1, 2 10/100MBase-T, 1 RS232 Console, SIP1.0/2.0, PRI, SS7 TUP/ISUP protocol)

Dinstar License G.723/G.729/ILBC

Dinstar License SS7

Dinstar License R2

IP телефоны

Dinstar DIT205 (2*SIP accounts, 4*softkesy;10*multifunction·WAN + 1 LAN; 128*32 Graphic·10*BRF·headset jack)

Dinstar DIT252 (WAN + LAN, 5*SIP accounts,·5*line keys/soft keys, 128*64 Graphic LCD, RJ22 headset·jack)

Dinstar EXP40 (поддерживается DIT252, расширение на 40 кнопок,·возможна работа с 4 мя EXP40)

Dinstar DIT300 (WIFI VoIP Phone;·1T1R 802.11N;·4 SIP accounts setting, 4 softkesy;·1WAN + 1 LAN;·128*64 Graphic LCD;)

Вер 032013
 

Установить geoip для Apache2 Debian

apt-get install -y libapache2-mod-geoip php5-geoip

Проверяем наличие модулей в Apache (путь может отличатся, проверить наличие файлов по указанным путям):

LoadModule geoip_module /usr/lib/apache2/modules/mod_geoip.so
GeoIPEnable On
GeoIPDBFile /usr/share/GeoIP/GeoIP.dat
GeoIPDBFile /usr/share/GeoIP/GeoLiteCity.dat

Возможно подгружаемый модуль окажется, всяко может быть, ищите:

#nano /etc/apache2/mods-enabled/geoip.load
#nano /etc/apache2/mods-enabled/geoip.conf
#nano /etc/apache2/mods-available/geoip.conf

Копируем регулярно обновляемую базу городов:

# wget http://www.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz
# gunzip GeoLiteCity.dat.gz
# mv GeoLiteCity.dat /var/lib/GeoIP/GeoLiteCity.dat
# wget http://geolite.maxmind.com/download/geoip/database/GeoLiteCountry/GeoIP.dat.gz
# gunzip GeoIP.dat.gz
# mv GeoIP.dat /var/lib/GeoIP/GeoIP.dat

Перегружаем Apache:

/etc/init.d/httpd restart
Сер 282013
 

Безопасность в PHP. Проверяем типы переменных.

Известно, что PHP относится к слабо типизированным языкам программирования. Что же это значит? Мы можем проводить различные операции между переменными разного типа, и получать «что-то» на выходе. С одной стороны, это удобно. Строка превращается в целое число, целое число может стать объектом, а объект плавно перейти в массив. Но любой программист при создании сайтов на языке php рано или поздно сталкивается с тем, что во многих случаях типы переменных следует приводить (или, как минимум, проверять перед началом использования).

Примечание: такое строгое отношение к переменным связано с тем, что большинство скриптов на php подвержено нездоровому вниманию злоумышленников с целью подстановки параметров различного типа в строке запроса сайта. Это может привести от генерации ошибки с раскрытием пути, по которому находится файл, вплоть до обхода некоторых ограничений. Например: повышения прав пользователя в ранних версиях WordPress путём передачи имени пользователя как массива, а не строки, в скрипт аутентификации в admin панели, или же подстановки в строку запроса вместо целых чисел (например, id новости) – специально сформированных запросов sql с целью несанкционированного доступа, создание на сайте так называемых sql инъекций.

Так что, по возможности, проверяйте типы переменных перед их использованием или явно приводите их во время программирования на PHP.

Приведём функции, которые будут нам полезны с целью контроля безопасности входных данных:

(string) trim($str) – Принимаемые параметры: $var – строка для удаления пробельных символов и символов разрыва строки. Обрезает символы конца строки и пробельные символы вначале и конце строки, возвращает переменную строкового типа.
(bool) is_string($var) – Принимаемые параметры: $var – переменная для проверки. Является ли переменная $var строкой? Возвращает: true: если является, false: если не является.
(bool) is_numeric($var) – Принимаемые параметры: $var – переменная для проверки. Является ли переменная $var набором цифр ? Возвращает: true: если является, false: если не является.
(bool) is_float($var) – Принимаемые параметры: $var – переменная для проверки. Является ли переменная $var вещественным числом? Возвращает: true: если является, false: если не является.
(bool) is_array($var) – Принимаемые параметры: $var – переменная для проверки. Является ли переменная $var массивом? Возвращает: true: если является, false: если не является.
(bool) is_int($var) – Принимаемые параметры: $var – переменная для проверки. Является ли переменная $var целым числом? Возвращает: true: если является, false: если не является.
(bool) isset($var) – Принимаемые параметры: $var – переменная для проверки. Проверяет, существует ли переменная $var (любой тип данных), если существует, возвращает true, иначе возвращает false.
(bool) is_resource($var) – Принимаемые параметры: $var – переменная для проверки. Является ли переменная $var ресурсом? Возвращает: true: если является, false: если не является.
(bool) empty($var) – Принимаемые параметры: $var – переменная для проверки. Проверяет, пуста ли существующая переменная или нет, возвращаемые значения: true для значений (“”, 0, 0.0, “0”, NULL,FALSE,array()), false в остальных случаях
Пример использования при программировании в PHP скриптах:

Передаем в форму через пост запрос массив данных $user, полученный при регистрации пользователя:

<?php
        $user               = $_POST["user"];
        $sizeof             = sizeof($user);
        $username           = "";
        $password           = "";
        $user_id            = 0;
if(is_array($user) && $sizeof && isset($user["username"]) && isset($user["password"];)){
        $username           = trim($user["username"]);
        $password           = trim($user["password"]);
        $password           = is_int($user["user_id"]) ? $user["user_id"]: 0;
}
?>

Еще один пример использования в PHP скриптах:

Зададим вопрос к базе данных:

<?php
        $query              = "SELECT `news_text` FROM `news` WHERE `news_id`=5";
        $p                  = mysql_query($query);
        if($p && is_resource($p)){
            list($news_text)= mysql_fetch_row($p);
        }
?>

Замечание: дело в том, что очень полезно проверять, является ли параметр ресурсом, перед передачей функции, заведомо требующей параметр типа ресурс. Например, в случае sql запросов такой подход может подсказать об ошибке, которая произошла в запросе, или попросту о том, что сервер базы данных (или текущее подсоединение) занято.

Сер 282013
 

Безопасность в PHP. Явное приведение типов.

Операторы прямого приведения данных.

Совет: там, где от этого зависит безопасность, или результат может быть неоднозначным, приводите явно тип данных, проверяйте входящие переменные со стороны клиента на существование, пусты ли они, и к какому типу относятся. Аккуратность написания скриптов избавит от чрезмерной отладки в дальнейшем и сделает Ваш сайт менее чувствительным к действиям недоброжелателей,и более стабильным в работе.

Приведём несколько операндов, которые позволяют сделать это легко и без особых усилий при программировании на языке PHP, а так же поговорим о функциях приведения типов.

Примечание автора: операторы не изменяют тип переменной, но делает попытку приведения переменной и возвращает значение соответствующего типа.

$var = (int)$some_var, (integer)$some_var – явное приведение переменной $some_var к целочисленному типу
$var = (float)$some_var, (real)$some_var, (double)$some_var – явное приведение переменной $some_var к вещественному типу
$var = (array)$some_var – явное приведение переменной $some_var к массиву
$var = (string)$some_var – явное приведение переменной $some_var к массиву
$var = (bool)$some_var, (boolean)$some_var – явное приведение переменной $some_var логическому значению (true,false)
$var = (object)$some_var – явное приведение переменной $some_var к объекту
Новшества PHP 5:

(unset)$some_var – присвоение типа NULL, уничтожение переменной, освобождение памяти.
Новшества PHP 5.2.1:

(binary) $some_var – приведение переменной к бинарному представлению.
Примеры использования:

Рассмотрим передачу id статьи через массив GET news.php?id=23

Вариант подготовки параметра для безопасной передачи в запрос к базе данных:

?
1
$news_id = (int)$_GET[“id”];
Еще одной интересной функцией является abs, которую советую применять при фильтрации входных данных для заведомо неотрицательных величин, например уникального идентификатора статьи, который является по умолчанию числом уникальным, положительным, с auto increment:

abs($var) – Принимаемые параметры: $var – переменная целого (или вещественного) типа. Возвращает абсолютное по модулю число: для всех отрицательных величин возвращается положительное, для всех положительных возвращается просто значение переменной

Рассмотрим предыдущий пример в новом ракурсе:

Так как integer может быть как положительным, так и отрицательным целым числом, перепишем предыдущий пример с использованием функции abs:

Вариант подготовки параметра для безопасной передачи в запрос к базе данных:

?
1
$news_id = abs((int)$_GET[“id”]);
Функции явного приведения данных.

(int) intval($var,[$base = 10]) – Принимаемые параметры: $var – переменная для приведения типов. Приводит переменную к целочисленному типу. Возвращает переменную, приведенную к целочисленному типу, в случае с массивом 0 если массив пуст, 1 – если есть элементы, в случае со строкой: если удаётся преобразовать к целому числу – то целое число, или 0 в обратном случае.

$base = основание, десятичная система исчисления по умолчанию.

(float) floatval($var) – Принимаемые параметры: $var – переменная для приведения типов. Приводит переменную к вещественному типу. Возвращает переменную, приведенную к вещественному типу, в случае неудачи возвращает 0.
(bool) settype(&$var, string $type ) – Принимаемые параметры: $var – переменная для приведения типов, $type – к какому типу привести переменную:

“boolean”,”bool” – приведение типа переменной к логическому значению (true, false),
“integer”,”int” – приведение типа переменной к целому значению,
“float”,”double” – приведение типа переменной к вещественному значению,
“string” – приведение типа переменной к строковому значению,
“array” – приведение к массиву,
“object” – приведение типа переменной к объекту,
“null” – приведение типа переменной к типу NULL (освобождение занимаемой памяти).
Производит прямое приведение переменной к значению указанного типа. В случае удачи возвращает true, иначе – false.

Общирный пример практического использования вышеописанных функций при программировании на языке PHP:

Приведём пример безопасного запроса к базе данных с получением id новости из строки запроса:

<?php
$id             = isset($_GET["id"]) ? abs(intval($_GET["id"])) : 0;
If(!empty($id)){
    $q          = "SELECT `news_text` FROM `news` WHERE `news_id`=".$id;
    $p          = mysql_query($q);
    if($p && is_resource($p)){
    list($text) = mysql_fetch_row($p);
    echo $text;
}
}
?>
Сер 282013
 

Изучаем PHP. Пишем parser похожих запросов Yandex.

В жизни программиста очень часто возникает задача получения полезной информации из других источников. Это может быть всесторонняя оценка цен конкурентов по определённому товару, сбор изображений и описаний для автоматизации процесса загрузки новых позиций в интернет – магазин, поиск аудио и видео – информации и многое другое.

Здесь на выручку нам так называемый «скрипт – парсер». В задачу которого входит получение и проверка информации, поиск нужных фрагментов и исключение «мусора».

Рассмотрим на примере так называемый «parser – spider» (парсер – паук), в задачу которого будет входить сбор информации со страниц yandex для поиска похожих ключевых слов, которые мы будем использовать в раскрутке нашего проекта. И напишем данный парсер на PHP

Как же нам может помочь parser?
Мы получаем список сходных фраз, которыми пользуются посетители яндекса при поиске нашей тематики, и в дальнейшем сможем ориентироваться на них при написании материалов на нашем сайте, оцениваем спрос к тематике нашего сайта. А так же это даст нам возможность определить поисковые запросы с меньшей конкурентной борьбой сходной тематики, чтобы выйти по ним в ТОП поисковой системы Yandex. Как следствие, благодаря этой информации мы расширим аудиторию нашего проекта.

А откуда мы можем получить информацию по похожим поисковым запросам Yandex?
Дело в том, что при поиске Яндекс подсказывает сам, отображая блок внизу страницы: Вместе с «[фраза для поиска]» ищут – несколько подобных поисковых запросов.

Вверху в левой части каждой страницы указывает, сколько нашлось вариантов, например:
создать сайт – Нашлось 104 млн ответов

Итак, какие же задачи поставим перед скриптом – парсером?

Возможность рекурсивного парсинга похожих поисковых запросов с определением уровня вложенности
Если не найдено ни одного похожего запроса по указанной фразе (а такое тоже бывает), попробуем просмотреть запросы по её сокращению:

Например, если ввести фразу Создать Сайт Харьков, то похожих поисковых запросов не будет в выдаче поисковика, но если ввести: создать сайт – они появятся. Ограничимся урезанием фразы на одно слово вконце.

Обходить парсер будет не только одну фразу, а займётся обработкой целого списка из фраз (передадим массивом)
Сохранение найденных поисковых фраз и их встречаемостью в файл
Нюансы:

Поставим задержку на опрос поисковой системы (не меньше 2 секунд, а то и до 30 секунд в случайном порядке) на каждый поисковый запрос. Мы же не хотим, чтобы Яша нас «отругал» за плохое поведение?

<?php
function getURIContent($url){
        $tuCurl                         = curl_init();
        $tuData                         = '';
        if($tuCurl && is_resource($tuCurl)){
                $opts                   = array(
                CURLOPT_URL             => $url,
                CURLOPT_HTTPGET         => 1,
                CURLOPT_HEADER          => 0,
                CURLOPT_RETURNTRANSFER  => 1,
                CURLOPT_FOLLOWLOCATION  => 1,
                CURLOPT_BINARYTRANSFER  => 1,
                CURLOPT_AUTOREFERER     => 1,
                CURLOPT_CONNECTTIMEOUT  => 90,
                CURLOPT_USERAGENT       => $_SERVER['HTTP_USER_AGENT'],
                CURLOPT_COOKIEJAR       => dirname(__FILE__)."/cookie.txt",
                CURLOPT_COOKIEFILE      => dirname(__FILE__)."/cookie.txt",
                CURLOPT_REFERER         => $url
                                         );
        foreach($opts as $key=>$value){
          curl_setopt($tuCurl,$key,$value);
        }
        $tuData   = curl_exec($tuCurl);
        curl_close($tuCurl);
        }
        return $tuData;
}
function parseRecursive($question,$max_depth,$first = true){
    global $time_wait;
    $time_wait  = $time_wait < 2 ? 2 : $time_wait;
    $rand       = mt_rand($time_wait, $time_wait + 30);
    sleep($rand);
    $question   = urlencode($question);
    $where      = 'http://yandex.ua/yandsearch?text='.$question;
    $content    = getURIContent($where);
    $found      = false;
    if(!empty($content)){
        $how_many= array();
        preg_match_all('~<strong[^>]*?class="b-head-logo__text"[^>]*?>(.*?)</strong>~is',$content,$how_many);
        $numbers= '';
        if(is_array($how_many)
                     && isset($how_many[1][0])
                           && !empty($how_many[1][0])){
            $numbers   = trim($how_many[1][0]);
            $numbers   = preg_replace("~<br[^>]*?>~is",' ', $numbers);
            $numbers   = str_ireplace("&nbsp;",' ', $numbers);
            $numbers   = str_ireplace("\r\n",' ', $numbers);
            $numbers   = str_ireplace("\r",' ', $numbers);
            $numbers   = str_ireplace("\n",' ', $numbers);
            $numbers   = str_ireplace("\t",' ', $numbers);
            $numbers   = str_ireplace("\p",' ', $numbers);
            $numbers   = str_ireplace("\b",' ', $numbers);
            $numbers   = html_entity_decode($numbers,ENT_QUOTES,'UTF-8');
            $numbers   = strip_tags($numbers);
        }
        if(!empty($numbers)){
            $numbers = urldecode($question) . ' - ' . $numbers. "\n";
            $fp = fopen(WHERE_TO_SAVE,'a+');
            if($fp && is_resource($fp)){
                echo 'ADDING '.$numbers. "<br />\n";
                flock($fp,LOCK_EX);
                fwrite($fp,$numbers);
                flock($fp,LOCK_UN);
                fclose($fp);
            }
        }
        $related= array();
        $links  = array();
        preg_match_all('~<table[^>]*?class="b-related__table"[^>]*?>(.*?)</table>~is',$content,$related);
        /* <a[^>]*?href=("|\')([^"\']*?)(\1)[^>]*?>(.*?)</a> */
        if(is_array($related[1]) &&
                    isset($related[1][0])
                        && $max_depth){
            --$max_depth;
            preg_match_all('~<a[^>]*?href=("|\')([^"\']*?)(\1)[^>]*?>(.*?)</a>~is',$related[1][0],$links);
            if(is_array($links)
                           && isset($links[2])
                                && isset($links[4])
                                     && sizeof($links[2])
                                && sizeof($links[4])
                                     && $max_depth){
                $sizeof     = sizeof($links[4]);
                for($i = 0; $i < $sizeof; $i ++){
                    $text   = '';
                    $text   = trim($links[4][$i]);
                    $text   = preg_replace("~<br[^>]*?>~is",' ', $text);
                    $text   = str_ireplace("&nbsp;",' ', $text);
                    $text   = str_ireplace("\r\n",' ', $text);
                    $text   = str_ireplace("\r",' ', $text);
                    $text   = str_ireplace("\n",' ', $text);
                    $text   = str_ireplace("\t",' ', $text);
                    $text   = str_ireplace("\p",' ', $text);
                    $text   = str_ireplace("\b",' ', $text);
                    $text   = html_entity_decode($text,ENT_QUOTES,'UTF-8');
                    $text   = strip_tags($text);
                    if(!empty($links[2][$i]) && !empty($text)){
parseRecursive($text,$max_depth,false);
                    }
                }
            }
        } elseif (is_array($related[1]) && $max_depth){
            $question    = urldecode($question);
            $words= array();
            $words= explode(' ',$question);
            $sizeof= sizeof($words);
            $words= array_map('trim',$words);
            --$sizeof;
            $words= array_slice($words,0,$sizeof);
            $question    = join(' ',$words);
            if(strlen($question) > 4){
                --$max_depth;
                if($max_depth){
                parseRecursive($question,$max_depth,false);
                }
            }
        }
    }
}
ini_set('max_execution_time',999999);
ini_set('max_input_time',999999);
$max_depth      = 2;
$time_wait      = 2;
$questions      = array('создать сайт',
                          'сайт на joomla',
                          'создать сайт Харьков',
                          'сайт на wordpress');
define('WHERE_TO_SAVE',dirname(__FILE__).'/prases.txt');
if(!is_file(WHERE_TO_SAVE)){
    $fp  = fopen(WHERE_TO_SAVE,'w+');
    if($fp && is_resource($fp)){
        fclose($fp);
    }
    if(is_file(WHERE_TO_SAVE) && !is_writable(WHERE_TO_SAVE)){
        chmod(WHERE_TO_SAVE,0777);
    }
}
if(is_file(WHERE_TO_SAVE)){
    $fp  = fopen(WHERE_TO_SAVE,'w+');
    if($fp && is_resource($fp)){
        fclose($fp);
    }
}
if(is_file(WHERE_TO_SAVE) && is_writable(WHERE_TO_SAVE)){
    $sizeof     = sizeof($questions);
    for($i = 0; $i < $sizeof; $i ++){
        parseRecursive($questions[$i],$max_depth);
    };
};
?>

Итак, что же здесь происходит:

Для начала с помощью ini_set установим побольше время выполнения для скрипта.

В переменной $max_depth укажем, сколько вложенных уровней «обходить» (на какую глубину «погружаться») для сбора похожих фраз.

Например: $max_depth = 2; – находим похожие поисковые фразы, переходим по каждой из них, и собираем результаты по похожим уже на них поисковым фразам.

Совет: не делайте слишком большим уровень вложенности. Иначе сильно отклонитесь от первоначальной тематической фразы.

Переменной $time_wait указываем, сколько секунд ждать до следующего запроса к поисковику.

Обратите внимание – 2 секунды – это минимальное значение. Иначе сайт выдаст вам капчу или наложит бан по ай-пи адресу.

В массив $questions = array(‘создать сайт’,’сайт на joomla’,’создать сайт Харьков’,’сайт на wordpress’); – списком строк через запятую добавляем запросы для обработки parser ом.

Далее, определяем, существует ли файл prases.txt – в который мы и добавим найденный результат. Если не существует, создаём его и делаем доступным на запись.

После этого обходим массив $questions и передаём каждый запрос функции parseRecursive вместе с уровнем вложения.

(void) function parseRecursive($question,$max_depth,$first = true): принимает одну поисковую фразу (string)$questions[$i] и уровень вложенности поиска $max_depth, а так же неявный флаг (bool) $first, для определения, в какой раз подряд вызывается функция (для чего, рассмотрим ниже).

В функции мы кодируем для возможности передачи в виде запроса нашу ключевую фразу с помощью urlencode и получаем содержимое запроса в функции getURIContent, основанной на curl. После чего регулярным выражением ~]*?class=”b-head-logo__text”[^>]*?>(.*?)~is узнаём, сколько раз встречается данный поисковой запрос.

Очищаем полученный запрос от html и спец символов. Помещаем выражение и количество найденных страниц по этой поисковой фразе в файл prases.txt.

Исследуем содержимое полученной страницы на предмет содержания «похожих поисковых запросов» ~]*?class=”b-related__table”[^>]*?>(.*?)

~is.

Если похожие поисковые фразы найдены, извлекаем ссылки на них и их анкоры: ~]*?href=(“|’)([^”‘]*?)(\1)[^>]*?>(.*?)~is

При этом уменьшая на единицу наш уровень вложенности –$max_depth

Если уровень вложенности позволяет (отличен от нуля), передаём анкоры (текст, заключённый в тег a) рекурсивно в функцию parseRecursive. Обрабатываем следующий уровень.

Если же на странице не было найдено по указанной поисковой фразе ни одного результата, и вызов функции parseRecursive был осуществлён впервые (неявный флаг $first со значением true) то проверяем, содержит ли слова поисковый запрос? (Разбиваем по пробельному символу фразу на слова). Исключаем последнее слово, и передаём полученное словосочетание заново функции parseRecursive.

Примечание автора: для получения содержимого страниц по указанным поисковым запросам используется функция getURIContent, которая принимает адрес страницы и возвращает её содержимое.

Её работа основывается на curl, что даёт ряд преимуществ перед url wrapper ами функции file, fopen, file_get_contents и т.п.:

Более быстрый процесс получения информации
Передача referrer, cookie, user agent
Управление временем ожидания (таймаутом) на получение информации
Возможность корректно перейти по всем пере направлениям (Location:), если таковые встречаются
Бинарная передача данных
В следующих статьях мы поведаем Вам более подробно о возможностях функции curl и приведём другие интересные примеры её использования.

Замечание: каждый программист должен задаваться не только вопросом, что было сделано хорошо, но и «а что можно было бы сделать лучше» (оптимизация кода, повышение качества результата, удобная подача информации и т.п.).

Убрать дубли фраз, обнаруженные при поиске.
Для получения более достоверных вариантов проверять, встречается хотя бы одно слово из целевого поискового словосочетания, заданного в $questions в фразах, обнаруженных при многоуровневом обходе страниц
Каждый результат поиска записать в отдельный файл.
Визуализировать результат при помощи графиков
Задание для тех, кто учит parser ы на PHP:
Для выполнения этой же задачи напишите парсер, который обходит wordstat yandex