Продвинутая отправка уведомлений

Только готовые уроки по использованию ВКонтакте API. Flash + PHP + API. НЕ IFrame!
Noise Gate
Сообщения: 691
Зарегистрирован: 28 апр 2010, 12:34

Продвинутая отправка уведомлений

Сообщение Noise Gate »

В этом уроке мы научимся отсылать уведомления пользователям и получать "отчеты о доставке", которые будем регистрировать в БД.

Для начала нам понадобится таблица delivery, в которой будут содержаться uids пользователей, а также параметр undelivered для каждого uid, который будет показывать, сколько из отосланных этому пользователю сообщений не было доставлено.

Код: Выделить всё

CREATE TABLE delivery(uid INT UNSIGNED NOT NULL DEFAULT 0,                   -- uid пользователя в VK undelivered INT UNSIGNED NOT NULL DEFAULT 0,        -- сколько раз недоставлено сообщение PRIMARY KEY(uid))ENGINE MyISAM CHARACTER SET utf8;
Когда эта таблица будет заполнена uid пользователей, мы сможем отправлять им сообщения с фильтрацией по параметру undelivered.
Если параметр undelivered отличен от нуля - это значит, что сообщения пользователю не доставляются: какому числу равен undelivered, столько сообщений и не было доставлено. Если undelivered растет, то скорее всего пользователь уже удалил приложение или запретил присылать ему уведомления. Таким образом, нет смысла высылать уведомления пользователям с высоким показателем undelivered.

Введем еще один параметр - threshold, который будет определять пользователей для доставки уведомлений.
Если undelivered<threshold, то уведомления будут высылаться, в противном случае пользователь считается неактивным.

Затронем еще один вопрос - какое число пользователей будет запрашиваться из БД за один раз. Если оно будет мало, то это обернется большим числом запросов к БД, если слишком велико - может привести к проблемам с выделением памяти. Введем для этого еще один параметр - n_per_page (списки пользователей как бы делятся на "страницы" по n_per_page штук на каждой).

С учетом всего выше сказанного получаем следующий скрипт:

Код: Выделить всё

<?php // Настройки БД$db_name = 'sample';            // Название базы данных$db_user = 'sample';            // Имя пользователя для MySQL$db_pass = 'sample';            // ...и пароль$db_host = 'localhost';         // с вероятностью 99% вам не нужно менять это значение$delivery_table = 'delivery';   // Название таблицы // Соединяемся, выбираем базу данных$dblink = mysql_connect($db_host, $db_user, $db_pass) or die(mysql_error());$dbselected = mysql_select_db($db_name, $dblink) or die(mysql_error()); // Настройки приложения$api_id = 111;$api_secret = 'sample'; // Сообщение и настройки отсылки$message = 'test message';$threshold = 10;$n_per_page = 10000;  // ***************************************************************************** // Подключаем API-класс ( * о нем будет написано ниже * )include 'vkapixml.class.php'; $total_delivered_count = 0;         // сколько всего доставлено сообщений // Определяем общее кол-во получателей из базы$dbquery = "SELECT COUNT(*) FROM $delivery_table WHERE undelivered<$threshold";$dbresult = mysql_query($dbquery) or die(mysql_error());if ( $dbresult ) {    $total_users = intval(mysql_result($dbresult,0));} else {    $total_users = 0;    die();} // Делим на "страницы" (для постепенного вывода из БД)$total_pages = ceil($total_users / $n_per_page); echo "Количество получателей: $total_users ($total_pages страниц по $n_per_page получателей) <br/>"; // Выдергиваем получателей постранично...for ($i = 0; $i < $total_pages; $i++) {        echo "Страница: ".($i+1)." из $total_pages. <br/>";        $dbquery = "SELECT * FROM $delivery_table WHERE undelivered<$threshold ORDER BY uid LIMIT ".($i*$n_per_page).", $n_per_page";    $dbresult = mysql_query($dbquery) or die(mysql_error());    $recipient_array = array();        // Получатели с текущей страницы    while ($row = mysql_fetch_assoc($dbresult)) {        $recipient_array[] = $row['uid'];    }    echo count($recipient_array).' получателей. <br/>';        // Отсылка n_per_page (recipient_array count) сообщений     $delivered_count = 0;    $undelivered_count = 0;    $uids_array = array_chunk($recipient_array, 100);   // делим страницу на куски по 100 получателей    foreach ($uids_array as $uids_item) {                set_time_limit(60);                // Отсылка одной партии (100 получателей)        $uids_string = implode(',', $uids_item);        $VK = new vkapi($api_id, $api_secret);        $answer = $VK->api('secure.sendNotification', array('uids'=>$uids_string,'message'=>$message));                // Парсим ответ        $pattern = '/<response>([\d\,]*)<\/response>/i';        if ( preg_match($pattern, $answer, $matches) > 0 ) {            $delivered_string = $matches[1];            $delivered_array = explode(',', $matches[1]);            $delivered_count += count($delivered_array);        } else {            $delivered_string = '';            $delivered_array = array();        }                // Вычисляем недоставленные сообщения        $undelivered_array = array_diff($uids_item,$delivered_array);        $undelivered_string = implode(',', $undelivered_array);        $undelivered_count += count($undelivered_array);                // фиксируем недоставленные в базе        if ( count($undelivered_array) > 0 ) {            $dbquery = "UPDATE $delivery_table SET undelivered=undelivered+1 WHERE uid IN ($undelivered_string)";            $dbresult = mysql_query($dbquery) or die(mysql_error());        }                // фиксируем доставленные в базе        if ( count($delivered_array) > 0 ) {            $dbquery = "UPDATE $delivery_table SET undelivered=undelivered-1 WHERE undelivered>0 AND uid IN ($delivered_string)";            $dbresult = mysql_query($dbquery) or die(mysql_error());        }            }        echo "Доставлено $delivered_count сообщений. Не доставлено - $undelivered_count. <br/>";        $total_delivered_count += $delivered_count;} echo "Всего доставлено $total_delivered_count сообщений из $total_users.";  ?>
ВАЖНО!
Скрипт использует файл vkapixml.class.php - это обычный vkapi.class.php ( http://vkontakte.ru/source/APIServerPHPClass.zip ), переделанный так, чтобы выдавать ответы в XML, а не в объекте JSON.
Вот мой вариант (vkapixml.class.php):

Код: Выделить всё

<?php /** * VKAPI class for vk.com social network * * @package server API methods * @link http://vk.com/developers.php * @autor Oleg Illarionov * @version 1.0 */ class vkapi {    var $api_secret;    var $app_id;    var $api_url;        function vkapi($app_id, $api_secret, $api_url = 'api.vk.com/api.php') {        $this->app_id = $app_id;        $this->api_secret = $api_secret;        if (!strstr($api_url, 'http://')) $api_url = 'http://'.$api_url;        $this->api_url = $api_url;    }        function api($method,$params=false) {        if (!$params) $params = array();         $params['api_id'] = $this->app_id;        $params['v'] = '3.0';        $params['method'] = $method;        $params['timestamp'] = time();        $params['format'] = 'xml';//      $params['format'] = 'json';        $params['random'] = rand(0,10000);        ksort($params);        $sig = '';        foreach($params as $k=>$v) {            $sig .= $k.'='.$v;        }        $sig .= $this->api_secret;        $params['sig'] = md5($sig);        $query = $this->api_url.'?'.$this->params($params);        $res = file_get_contents($query);        return $res;//      return json_decode($res, true);    }        function params($params) {        $pice = array();        foreach($params as $k=>$v) {            $pice[] = $k.'='.urlencode($v);        }        return implode('&',$pice);    }}?> 
Хинт для продвинутых
Чтобы обновлять данные о параметре undelivered, можно не уменьшать его на единицу при успешной доставке (строки 96-100 ), а обнулять. Но лично я обнуляю его только в том случае, когда пользователь заходит в приложение.
Аватара пользователя
boombast1k
Сообщения: 332
Зарегистрирован: 23 июн 2011, 07:31

Re: Продвинутая отправка уведомлений

Сообщение boombast1k »

Спасибо :)
Аватара пользователя
boombast1k
Сообщения: 332
Зарегистрирован: 23 июн 2011, 07:31

Re: Продвинутая отправка уведомлений

Сообщение boombast1k »

а можно как то переделать под базу http://flapps.ru/forum/topic753.html ?
Noise Gate
Сообщения: 691
Зарегистрирован: 28 апр 2010, 12:34

Re: Продвинутая отправка уведомлений

Сообщение Noise Gate »

ну да, конечно)) надо просто добавить туда еще одно поле - undelivered
Аватара пользователя
boombast1k
Сообщения: 332
Зарегистрирован: 23 июн 2011, 07:31

Re: Продвинутая отправка уведомлений

Сообщение boombast1k »

понятно, спасибо.
rail111
Сообщения: 10
Зарегистрирован: 14 авг 2011, 16:07

Re: Продвинутая отправка уведомлений

Сообщение rail111 »

В чем причина ошибки:

Код: Выделить всё

Warning: preg_match() expects parameter 2 to be string, array given in /home/u933632328/public_html/index.php on line 76
И почему когда сообщение доставлено в бае таблици "undelivered" не минусуется начение а плюсуется?
rail111
Сообщения: 10
Зарегистрирован: 14 авг 2011, 16:07

Re: Продвинутая отправка уведомлений

Сообщение rail111 »

Все. Перевел массив в строку и все нормуль.

Код: Выделить всё

<?php // Настройки БД$db_name = 'sample';            // Название базы данных$db_user = 'sample';            // Имя пользователя для MySQL$db_pass = 'sample';            // ...и пароль$db_host = 'localhost';         // с вероятностью 99% вам не нужно менять это значение$delivery_table = 'delivery';   // Название таблицы // Настройки приложения$api_id = 111;$api_secret = 'sample'; // Сообщение и настройки отсылки$message = 'test message';$threshold = 10;$n_per_page = 10000;  // ***************************************************************************** // Подключаем API-класс ( http://vkontakte.ru/source/APIServerPHPClass.zip )include 'vkapi.class.php'; $total_delivered_count = 0;         // сколько всего доставлено сообщений // Определяем общее кол-во получателей из базы$dbquery = "SELECT COUNT(*) FROM $delivery_table WHERE undelivered<$threshold";$dbresult = mysql_query($dbquery) or die(mysql_error());if ( $dbresult ) {    $total_users = intval(mysql_result($dbresult,0));} else {    $total_users = 0;    die();} // Делим на "страницы" (для постепенного вывода из БД)$total_pages = ceil($total_users / $n_per_page); echo "Количество получателей: $total_users ($total_pages страниц по $n_per_page получателей) <br/>"; // Выдергиваем получателей постранично...for ($i = 0; $i < $total_pages; $i++) {        echo "Страница: ".($i+1)." из $total_pages. <br/>";        $dbquery = "SELECT * FROM $delivery_table WHERE undelivered<$threshold ORDER BY uid LIMIT ".($i*$n_per_page).", $n_per_page";    $dbresult = mysql_query($dbquery) or die(mysql_error());    $recipient_array = array();        // Получатели с текущей страницы    while ($row = mysql_fetch_assoc($dbresult)) {        $recipient_array[] = $row['uid'];    }    echo count($recipient_array).' получателей. <br/>';        // Отсылка n_per_page (recipient_array count) сообщений     $delivered_count = 0;    $undelivered_count = 0;    $uids_array = array_chunk($recipient_array, 100);   // делим страницу на куски по 100 получателей    foreach ($uids_array as $uids_item) {                set_time_limit(60);                // Отсылка одной партии (100 получателей)        $uids_string = implode(',', $uids_item);        $VK = new vkapi($api_id, $api_secret);        $answe = $VK->api('secure.sendNotification', array('uids'=>$uids_string,'message'=>$message));        $answer = "$answe";        // Парсим ответ        $pattern = '/<response>([\d\,]*)<\/response>/i';        if ( preg_match($pattern, $answer, $matches) > 0 ) {            $delivered_string = $matches[1];            $delivered_array = explode(',', $matches[1]);            $delivered_count += count($delivered_array);        } else {            $delivered_string = '';            $delivered_array = array();        }                // Вычисляем недоставленные сообщения        $undelivered_array = array_diff($uids_item,$delivered_array);        $undelivered_string = implode(',', $undelivered_array);        $undelivered_count += count($undelivered_array);                // фиксируем недоставленные в базе        if ( count($undelivered_array) > 0 ) {            $dbquery = "UPDATE $delivery_table SET undelivered=undelivered+1 WHERE uid IN ($undelivered_string)";            $dbresult = mysql_query($dbquery) or die(mysql_error());        }                // фиксируем доставленные в базе        if ( count($delivered_array) > 0 ) {            $dbquery = "UPDATE $delivery_table SET undelivered=undelivered-1 WHERE undelivered>0 AND uid IN ($delivered_string)";            $dbresult = mysql_query($dbquery) or die(mysql_error());        }            }        echo "Доставлено $delivered_count сообщений. Не доставлено - $undelivered_count. <br/>";        $total_delivered_count += $delivered_count;} echo "Всего доставлено $total_delivered_count сообщений из $total_users.";  ?>
Noise Gate
Сообщения: 691
Зарегистрирован: 28 апр 2010, 12:34

Re: Продвинутая отправка уведомлений

Сообщение Noise Gate »

Да, точно! Прошу прощения. У меня просто vkapi.class.php переделан так, чтобы выдавать ответы в XML, а не в JSON

Вот мой вариант:

Код: Выделить всё

<?php /** * VKAPI class for vk.com social network * * @package server API methods * @link http://vk.com/developers.php * @autor Oleg Illarionov * @version 1.0 */ class vkapi {    var $api_secret;    var $app_id;    var $api_url;        function vkapi($app_id, $api_secret, $api_url = 'api.vk.com/api.php') {        $this->app_id = $app_id;        $this->api_secret = $api_secret;        if (!strstr($api_url, 'http://')) $api_url = 'http://'.$api_url;        $this->api_url = $api_url;    }        function api($method,$params=false) {        if (!$params) $params = array();         $params['api_id'] = $this->app_id;        $params['v'] = '3.0';        $params['method'] = $method;        $params['timestamp'] = time();        $params['format'] = 'xml';//      $params['format'] = 'json';        $params['random'] = rand(0,10000);        ksort($params);        $sig = '';        foreach($params as $k=>$v) {            $sig .= $k.'='.$v;        }        $sig .= $this->api_secret;        $params['sig'] = md5($sig);        $query = $this->api_url.'?'.$this->params($params);        $res = file_get_contents($query);        return $res;//      return json_decode($res, true);    }        function params($params) {        $pice = array();        foreach($params as $k=>$v) {            $pice[] = $k.'='.urlencode($v);        }        return implode('&',$pice);    }}?> 
Аватара пользователя
boombast1k
Сообщения: 332
Зарегистрирован: 23 июн 2011, 07:31

Re: Продвинутая отправка уведомлений

Сообщение boombast1k »

Можно кое о чем попросить? можешь сделать чтоб текст вводить на в самом php, а в форме? буду очень благодарен
kolu4iy
Сообщения: 3
Зарегистрирован: 21 ноя 2011, 09:53

Re: Продвинутая отправка уведомлений

Сообщение kolu4iy »

У меня не отправляется ничего. В чем может быть проблема?
Ответить