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

Только готовые уроки по использованию ВКонтакте API. Flash + PHP + API. НЕ IFrame!

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

Сообщение Noise Gate » 11 авг 2011, 16:25

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

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

  1. CREATE TABLE delivery
  2. (uid INT UNSIGNED NOT NULL DEFAULT 0,                   -- uid пользователя в VK
  3.  undelivered INT UNSIGNED NOT NULL DEFAULT 0,        -- сколько раз недоставлено сообщение
  4.  PRIMARY KEY(uid))
  5. ENGINE MyISAM CHARACTER SET utf8;


Когда эта таблица будет заполнена uid пользователей, мы сможем отправлять им сообщения с фильтрацией по параметру undelivered.
Если параметр undelivered отличен от нуля - это значит, что сообщения пользователю не доставляются: какому числу равен undelivered, столько сообщений и не было доставлено. Если undelivered растет, то скорее всего пользователь уже удалил приложение или запретил присылать ему уведомления. Таким образом, нет смысла высылать уведомления пользователям с высоким показателем undelivered.

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

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

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

  1. <?php
  2.  
  3. // Настройки БД
  4. $db_name = 'sample';            // Название базы данных
  5. $db_user = 'sample';            // Имя пользователя для MySQL
  6. $db_pass = 'sample';            // ...и пароль
  7. $db_host = 'localhost';         // с вероятностью 99% вам не нужно менять это значение
  8. $delivery_table = 'delivery';   // Название таблицы
  9.  
  10. // Соединяемся, выбираем базу данных
  11. $dblink = mysql_connect($db_host, $db_user, $db_pass) or die(mysql_error());
  12. $dbselected = mysql_select_db($db_name, $dblink) or die(mysql_error());
  13.  
  14. // Настройки приложения
  15. $api_id = 111;
  16. $api_secret = 'sample';
  17.  
  18. // Сообщение и настройки отсылки
  19. $message = 'test message';
  20. $threshold = 10;
  21. $n_per_page = 10000;
  22.  
  23.  
  24. // *****************************************************************************
  25.  
  26. // Подключаем API-класс ( * о нем будет написано ниже * )
  27. include 'vkapixml.class.php';
  28.  
  29. $total_delivered_count = 0;         // сколько всего доставлено сообщений
  30.  
  31. // Определяем общее кол-во получателей из базы
  32. $dbquery = "SELECT COUNT(*) FROM $delivery_table WHERE undelivered<$threshold";
  33. $dbresult = mysql_query($dbquery) or die(mysql_error());
  34. if ( $dbresult ) {
  35.     $total_users = intval(mysql_result($dbresult,0));
  36. } else {
  37.     $total_users = 0;
  38.     die();
  39. }
  40.  
  41. // Делим на "страницы" (для постепенного вывода из БД)
  42. $total_pages = ceil($total_users / $n_per_page);
  43.  
  44. echo "Количество получателей: $total_users ($total_pages страниц по $n_per_page получателей) <br/>";
  45.  
  46. // Выдергиваем получателей постранично...
  47. for ($i = 0; $i < $total_pages; $i++) {
  48.    
  49.     echo "Страница: ".($i+1)." из $total_pages. <br/>";
  50.    
  51.     $dbquery = "SELECT * FROM $delivery_table WHERE undelivered<$threshold ORDER BY uid LIMIT ".($i*$n_per_page).", $n_per_page";
  52.     $dbresult = mysql_query($dbquery) or die(mysql_error());
  53.     $recipient_array = array();
  54.    
  55.     // Получатели с текущей страницы
  56.     while ($row = mysql_fetch_assoc($dbresult)) {
  57.         $recipient_array[] = $row['uid'];
  58.     }
  59.     echo count($recipient_array).' получателей. <br/>';
  60.    
  61.     // Отсылка n_per_page (recipient_array count) сообщений
  62.     $delivered_count = 0;
  63.     $undelivered_count = 0;
  64.     $uids_array = array_chunk($recipient_array, 100);   // делим страницу на куски по 100 получателей
  65.     foreach ($uids_array as $uids_item) {
  66.        
  67.         set_time_limit(60);
  68.        
  69.         // Отсылка одной партии (100 получателей)
  70.         $uids_string = implode(',', $uids_item);
  71.         $VK = new vkapi($api_id, $api_secret);
  72.         $answer = $VK->api('secure.sendNotification', array('uids'=>$uids_string,'message'=>$message));
  73.        
  74.         // Парсим ответ
  75.         $pattern = '/<response>([\d\,]*)<\/response>/i';
  76.         if ( preg_match($pattern, $answer, $matches) > 0 ) {
  77.             $delivered_string = $matches[1];
  78.             $delivered_array = explode(',', $matches[1]);
  79.             $delivered_count += count($delivered_array);
  80.         } else {
  81.             $delivered_string = '';
  82.             $delivered_array = array();
  83.         }
  84.        
  85.         // Вычисляем недоставленные сообщения
  86.         $undelivered_array = array_diff($uids_item,$delivered_array);
  87.         $undelivered_string = implode(',', $undelivered_array);
  88.         $undelivered_count += count($undelivered_array);
  89.        
  90.         // фиксируем недоставленные в базе
  91.         if ( count($undelivered_array) > 0 ) {
  92.             $dbquery = "UPDATE $delivery_table SET undelivered=undelivered+1 WHERE uid IN ($undelivered_string)";
  93.             $dbresult = mysql_query($dbquery) or die(mysql_error());
  94.         }
  95.        
  96.         // фиксируем доставленные в базе
  97.         if ( count($delivered_array) > 0 ) {
  98.             $dbquery = "UPDATE $delivery_table SET undelivered=undelivered-1 WHERE undelivered>0 AND uid IN ($delivered_string)";
  99.             $dbresult = mysql_query($dbquery) or die(mysql_error());
  100.         }
  101.        
  102.     }
  103.    
  104.     echo "Доставлено $delivered_count сообщений. Не доставлено - $undelivered_count. <br/>";
  105.    
  106.     $total_delivered_count += $delivered_count;
  107. }
  108.  
  109. echo "Всего доставлено $total_delivered_count сообщений из $total_users.";
  110.  
  111.  
  112. ?>


ВАЖНО!
Скрипт использует файл vkapixml.class.php - это обычный vkapi.class.php ( http://vkontakte.ru/source/APIServerPHPClass.zip ), переделанный так, чтобы выдавать ответы в XML, а не в объекте JSON.
Вот мой вариант (vkapixml.class.php):
  1. <?php
  2.  
  3. /**
  4.  * VKAPI class for vk.com social network
  5.  *
  6.  * @package server API methods
  7.  * @link http://vk.com/developers.php
  8.  * @autor Oleg Illarionov
  9.  * @version 1.0
  10.  */
  11.  
  12. class vkapi {
  13.     var $api_secret;
  14.     var $app_id;
  15.     var $api_url;
  16.    
  17.     function vkapi($app_id, $api_secret, $api_url = 'api.vk.com/api.php') {
  18.         $this->app_id = $app_id;
  19.         $this->api_secret = $api_secret;
  20.         if (!strstr($api_url, 'http://')) $api_url = 'http://'.$api_url;
  21.         $this->api_url = $api_url;
  22.     }
  23.    
  24.     function api($method,$params=false) {
  25.         if (!$params) $params = array();
  26.         $params['api_id'] = $this->app_id;
  27.         $params['v'] = '3.0';
  28.         $params['method'] = $method;
  29.         $params['timestamp'] = time();
  30.         $params['format'] = 'xml';
  31. //      $params['format'] = 'json';
  32.         $params['random'] = rand(0,10000);
  33.         ksort($params);
  34.         $sig = '';
  35.         foreach($params as $k=>$v) {
  36.             $sig .= $k.'='.$v;
  37.         }
  38.         $sig .= $this->api_secret;
  39.         $params['sig'] = md5($sig);
  40.         $query = $this->api_url.'?'.$this->params($params);
  41.         $res = file_get_contents($query);
  42.         return $res;
  43. //      return json_decode($res, true);
  44.     }
  45.    
  46.     function params($params) {
  47.         $pice = array();
  48.         foreach($params as $k=>$v) {
  49.             $pice[] = $k.'='.urlencode($v);
  50.         }
  51.         return implode('&',$pice);
  52.     }
  53. }
  54. ?>
  55.  


Хинт для продвинутых
Чтобы обновлять данные о параметре undelivered, можно не уменьшать его на единицу при успешной доставке (строки 96-100 ), а обнулять. Но лично я обнуляю его только в том случае, когда пользователь заходит в приложение.
Noise Gate

 
Автор темы
Сообщения: 691
Зарегистрирован: 28 апр 2010, 12:34
Откуда: СПб
Благодарил (а): 31 раз.
Поблагодарили: 64 раз.

Чтобы убрать блок с рекламой, зарегистрируйтесь на форуме или войдите.

Google
 



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

Сообщение boombast1k » 11 авг 2011, 19:13

Спасибо :)
Аватара пользователя
boombast1k

 
Сообщения: 332
Зарегистрирован: 23 июн 2011, 07:31
Благодарил (а): 14 раз.
Поблагодарили: 14 раз.

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

Сообщение boombast1k » 16 авг 2011, 07:16

а можно как то переделать под базу http://flapps.ru/forum/topic753.html ?
Аватара пользователя
boombast1k

 
Сообщения: 332
Зарегистрирован: 23 июн 2011, 07:31
Благодарил (а): 14 раз.
Поблагодарили: 14 раз.

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

Сообщение Noise Gate » 16 авг 2011, 10:28

ну да, конечно)) надо просто добавить туда еще одно поле - undelivered
Noise Gate

 
Автор темы
Сообщения: 691
Зарегистрирован: 28 апр 2010, 12:34
Откуда: СПб
Благодарил (а): 31 раз.
Поблагодарили: 64 раз.

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

Сообщение boombast1k » 16 авг 2011, 13:29

понятно, спасибо.
Аватара пользователя
boombast1k

 
Сообщения: 332
Зарегистрирован: 23 июн 2011, 07:31
Благодарил (а): 14 раз.
Поблагодарили: 14 раз.

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

Сообщение rail111 » 18 авг 2011, 15:52

В чем причина ошибки:
  1. 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
Благодарил (а): 0 раз.
Поблагодарили: 0 раз.

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

Сообщение rail111 » 18 авг 2011, 17:49

Все. Перевел массив в строку и все нормуль.
  1. <?php
  2.  
  3. // Настройки БД
  4. $db_name = 'sample';            // Название базы данных
  5. $db_user = 'sample';            // Имя пользователя для MySQL
  6. $db_pass = 'sample';            // ...и пароль
  7. $db_host = 'localhost';         // с вероятностью 99% вам не нужно менять это значение
  8. $delivery_table = 'delivery';   // Название таблицы
  9.  
  10. // Настройки приложения
  11. $api_id = 111;
  12. $api_secret = 'sample';
  13.  
  14. // Сообщение и настройки отсылки
  15. $message = 'test message';
  16. $threshold = 10;
  17. $n_per_page = 10000;
  18.  
  19.  
  20. // *****************************************************************************
  21.  
  22. // Подключаем API-класс ( http://vkontakte.ru/source/APIServerPHPClass.zip )
  23. include 'vkapi.class.php';
  24.  
  25. $total_delivered_count = 0;         // сколько всего доставлено сообщений
  26.  
  27. // Определяем общее кол-во получателей из базы
  28. $dbquery = "SELECT COUNT(*) FROM $delivery_table WHERE undelivered<$threshold";
  29. $dbresult = mysql_query($dbquery) or die(mysql_error());
  30. if ( $dbresult ) {
  31.     $total_users = intval(mysql_result($dbresult,0));
  32. } else {
  33.     $total_users = 0;
  34.     die();
  35. }
  36.  
  37. // Делим на "страницы" (для постепенного вывода из БД)
  38. $total_pages = ceil($total_users / $n_per_page);
  39.  
  40. echo "Количество получателей: $total_users ($total_pages страниц по $n_per_page получателей) <br/>";
  41.  
  42. // Выдергиваем получателей постранично...
  43. for ($i = 0; $i < $total_pages; $i++) {
  44.    
  45.     echo "Страница: ".($i+1)." из $total_pages. <br/>";
  46.    
  47.     $dbquery = "SELECT * FROM $delivery_table WHERE undelivered<$threshold ORDER BY uid LIMIT ".($i*$n_per_page).", $n_per_page";
  48.     $dbresult = mysql_query($dbquery) or die(mysql_error());
  49.     $recipient_array = array();
  50.    
  51.     // Получатели с текущей страницы
  52.     while ($row = mysql_fetch_assoc($dbresult)) {
  53.         $recipient_array[] = $row['uid'];
  54.     }
  55.     echo count($recipient_array).' получателей. <br/>';
  56.    
  57.     // Отсылка n_per_page (recipient_array count) сообщений
  58.     $delivered_count = 0;
  59.     $undelivered_count = 0;
  60.     $uids_array = array_chunk($recipient_array, 100);   // делим страницу на куски по 100 получателей
  61.     foreach ($uids_array as $uids_item) {
  62.        
  63.         set_time_limit(60);
  64.        
  65.         // Отсылка одной партии (100 получателей)
  66.         $uids_string = implode(',', $uids_item);
  67.         $VK = new vkapi($api_id, $api_secret);
  68.         $answe = $VK->api('secure.sendNotification', array('uids'=>$uids_string,'message'=>$message));
  69.         $answer = "$answe";
  70.         // Парсим ответ
  71.         $pattern = '/<response>([\d\,]*)<\/response>/i';
  72.         if ( preg_match($pattern, $answer, $matches) > 0 ) {
  73.             $delivered_string = $matches[1];
  74.             $delivered_array = explode(',', $matches[1]);
  75.             $delivered_count += count($delivered_array);
  76.         } else {
  77.             $delivered_string = '';
  78.             $delivered_array = array();
  79.         }
  80.        
  81.         // Вычисляем недоставленные сообщения
  82.         $undelivered_array = array_diff($uids_item,$delivered_array);
  83.         $undelivered_string = implode(',', $undelivered_array);
  84.         $undelivered_count += count($undelivered_array);
  85.        
  86.         // фиксируем недоставленные в базе
  87.         if ( count($undelivered_array) > 0 ) {
  88.             $dbquery = "UPDATE $delivery_table SET undelivered=undelivered+1 WHERE uid IN ($undelivered_string)";
  89.             $dbresult = mysql_query($dbquery) or die(mysql_error());
  90.         }
  91.        
  92.         // фиксируем доставленные в базе
  93.         if ( count($delivered_array) > 0 ) {
  94.             $dbquery = "UPDATE $delivery_table SET undelivered=undelivered-1 WHERE undelivered>0 AND uid IN ($delivered_string)";
  95.             $dbresult = mysql_query($dbquery) or die(mysql_error());
  96.         }
  97.        
  98.     }
  99.    
  100.     echo "Доставлено $delivered_count сообщений. Не доставлено - $undelivered_count. <br/>";
  101.    
  102.     $total_delivered_count += $delivered_count;
  103. }
  104.  
  105. echo "Всего доставлено $total_delivered_count сообщений из $total_users.";
  106.  
  107.  
  108. ?>
rail111

 
Сообщения: 10
Зарегистрирован: 14 авг 2011, 16:07
Благодарил (а): 0 раз.
Поблагодарили: 0 раз.

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

Сообщение Noise Gate » 19 авг 2011, 10:08

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

Вот мой вариант:
  1. <?php
  2.  
  3. /**
  4.  * VKAPI class for vk.com social network
  5.  *
  6.  * @package server API methods
  7.  * @link http://vk.com/developers.php
  8.  * @autor Oleg Illarionov
  9.  * @version 1.0
  10.  */
  11.  
  12. class vkapi {
  13.     var $api_secret;
  14.     var $app_id;
  15.     var $api_url;
  16.    
  17.     function vkapi($app_id, $api_secret, $api_url = 'api.vk.com/api.php') {
  18.         $this->app_id = $app_id;
  19.         $this->api_secret = $api_secret;
  20.         if (!strstr($api_url, 'http://')) $api_url = 'http://'.$api_url;
  21.         $this->api_url = $api_url;
  22.     }
  23.    
  24.     function api($method,$params=false) {
  25.         if (!$params) $params = array();
  26.         $params['api_id'] = $this->app_id;
  27.         $params['v'] = '3.0';
  28.         $params['method'] = $method;
  29.         $params['timestamp'] = time();
  30.         $params['format'] = 'xml';
  31. //      $params['format'] = 'json';
  32.         $params['random'] = rand(0,10000);
  33.         ksort($params);
  34.         $sig = '';
  35.         foreach($params as $k=>$v) {
  36.             $sig .= $k.'='.$v;
  37.         }
  38.         $sig .= $this->api_secret;
  39.         $params['sig'] = md5($sig);
  40.         $query = $this->api_url.'?'.$this->params($params);
  41.         $res = file_get_contents($query);
  42.         return $res;
  43. //      return json_decode($res, true);
  44.     }
  45.    
  46.     function params($params) {
  47.         $pice = array();
  48.         foreach($params as $k=>$v) {
  49.             $pice[] = $k.'='.urlencode($v);
  50.         }
  51.         return implode('&',$pice);
  52.     }
  53. }
  54. ?>
  55.  
Noise Gate

 
Автор темы
Сообщения: 691
Зарегистрирован: 28 апр 2010, 12:34
Откуда: СПб
Благодарил (а): 31 раз.
Поблагодарили: 64 раз.

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

Сообщение boombast1k » 27 авг 2011, 22:31

Можно кое о чем попросить? можешь сделать чтоб текст вводить на в самом php, а в форме? буду очень благодарен
Аватара пользователя
boombast1k

 
Сообщения: 332
Зарегистрирован: 23 июн 2011, 07:31
Благодарил (а): 14 раз.
Поблагодарили: 14 раз.

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

Сообщение kolu4iy » 24 ноя 2011, 10:10

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

 
Сообщения: 3
Зарегистрирован: 21 ноя 2011, 09:53
Благодарил (а): 0 раз.
Поблагодарили: 0 раз.

След.

Вернуться в Уроки по использованию ВКонтакте API



Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 0

cron