Обращаю Ваше внимание, что в связи с нестабильной работой сервера почты Китая, а также с введением дополнительной проверки капчи скрипт chinapost.php стал нерабочим. Помимо этого в связи с хакерской атакой на сайт почты России 21 августа 2012 года изменился алгоритм работы скрипта rupost.php. Теперь при каждом запросе на отслеживание посылки, сайт Русской почты подсовывает Java-скрипт, содержащий уникальный номер. Если номер обратно не отправить серверу, то информацию об отправлении нам не получить. Скрипт rupost.php исправлен, архив source.rar актуализирован.

28 октября 2012 года


Примерно 14 ноября 2012 года на сайте почты России появилось нововведение, теперь чтобы отследить посылку необходимо ввести проверочный код с картинки (капчу). Как временное решение предлагаю использовать сервис antigate.com для заполнения проверочного кода. Измененный скрипт в открытый доступ не выкладываю, чтобы его получить необходимо в индивидуальном порядке обратиться ко мне на почту.

18 ноября 2012 года


PHP скрипт для отслеживания посылок

В последнее время я очень сильно увлекся покупками за рубежом – теперь просто не представляю, как раньше обходился без этого. Каждый месяц раз по пять-десять прихожу на почту и забираю посылки, пришедшие мне либо из Китая, либо из Америки. Заказываю в основном товары по различным акциям в интернет магазинах Китая и радиодетали, при этом понимая в какую лотерею, приходится играть с крупной государственной структурой, именуемой Почта России.

Вот и сейчас в ожидании 10 штук HT1632C, решил автоматизировать процесс отслеживания посылок. Для успешной реализации идеи нам потребуется виртуальный хостинг со следующими минимальными характеристиками: поддержка PHP (наличие модуля CURL), MySQL (необязательно), Cron. К счастью, у меня оказалась возможность «присоседится» к серверу, оплачиваемому моим знакомым. Для отправки СМС через интернет можно воспользоваться одним из следующих сервисов: 93W.RU, SMS-центр, "Простор", iqsms.ru, Yakoon, COMTUBE и другие. Средняя цена за отправку сообщений составляет 50 копеек, SMS можно отправлять с помощью GET или POST запросов, что является крайне удобным для нас.

Несмотря на обилие в интернете сервисов, предлагающих подобную услугу (специально не буду их рекламировать), у них у всех есть один большой недостаток – тарифы на SMS информирование. Кредиты, покупаемые у системы для отправки сообщений, очень быстро расходуются (с трудом хватает 50 рублей для отслеживания двух посылок). К тому же, имея собственную систему, можно определять период опроса почтовых сервисов, корректировать текст SMS и многое другое.

Сейчас расскажу о концепции проекта. За отслеживание посылки в каждой стране будет отвечать отдельный файл. Это связано с «непостоянством» почтовых сервисов – они то и дело норовят поменять протокол, а как следствие приходится изменять исходный код. На данный момент разработаны модули для отслеживания с помощью почтовых служб Китая (файл chinapost.php), Гонконга (файл hkpost.php), США (файл usps.php) и России (файл rupost.php). Стандартные функции, используемые в работе, также вынесены отдельным модулем.

Рассмотрим состав основного модуля (файл function.php). Самая значимая функция, которая отправляет POST-запрос на получение страницы, называется GetPostRequest. В качестве аргументов ей передается 2 параметра: $url – адрес страницы, $post_data – данные POST-запроса (если параметров несколько, то они разделяются знаком «&»). Функция использует библиотеку CURL и возвращает загруженную страницу.

Исходный код
function GetPostRequest($url,$post_data)
{
  $ch = curl_init();					//инициализируем библиотеку CURL
  curl_setopt($ch, CURLOPT_URL, $url);			//передаем URL
  curl_setopt($ch, CURLOPT_HEADER, 0);			//не передаем заголовки
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);		//получаем результат в переменную
  curl_setopt($ch, CURLOPT_POST, 1);			//указываем, что запрос POST
  curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);	//передаем параметры запроса
  $result = curl_exec($ch);				//выполняем CURL запрос
  curl_close($ch);					//закрываем CURL
  return $result;					//возвращаем результат
}

Если библиотека CURL по каким-то причинам недоступна, то функцию можно немного переделать. В таком варианте она спокойно «живет» на моем роутере D-Link DIR-320.

Исходный код
function GetPostRequest ($url, $data)
{
$parse =  parse_url($url);			//получаем ассоциативный массив
$url_host=$parse['host'];			//извлекаем имя хоста
$sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP) or die("Не работает\n"); //создаем сокет
socket_connect($sock, $url_host, 80);  		//соединяемся с сервером 
//формируем запрос
$request  = "POST ".$parse['path']." HTTP/1.1\r\n";
$request .= "Host: ".$url_host."\r\n";
$request .= "User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)\r\n";
$request .= "Content-type: application/x-www-form-urlencoded\r\n";
$request .= "Content-Length: ".strlen($data)."\r\n";
$request .= "Connection: Close\r\n\r\n";
$request .= $data;
//запрос сформирован 
socket_write($sock, $request);			//передаем запрос серверу
$buff= "";
do {
	$recv = "";
	$recv = socket_read($sock, '1400');	//считываем данные
	if($recv != "") 			//если данные не пустые
	{
		$buff .= $recv;			//дописываем их к буферу
	}
} while($recv != ""); 				//повторяем так до последнего байта
socket_close($sock);				//закрываем сокет
return $buff;					//возвращаем результат
}

После того, как страница успешно загружена, необходимо извлечь из неё нужные нам данные. Для этой операции разработана функция GetParamHTML, принимающая в качестве аргумента 4 параметра: $data – данные для парсинга, $stag – открывающий тэг, $endtag – закрывающий тэг, $offs – смещение от начала данных. Результатом выполнения функции будет фрагмент данных, заключенный между тэгами $stag и $endtag, если тэги не найдены, то будет возвращен код ошибки.

Исходный код
function GetParamHTML($data,$stag,$endtag,$offs)
{
  global $tmpend;			//используем глобальную переменную
  $tmppos=strpos($data,$stag,$offs);	//находим открывающий тэг
  if ($tmppos!==false)			//проверяем найден ли тэг
  {
  	$tmpend=strpos($data,$endtag,$tmppos)+strlen($endtag);	//находим закрывающий тэг
  	$result=substr($data,$tmppos,$tmpend-$tmppos);		//вырезаем фрагмент
  	return $result;			//возвращаем результат
  }
  else
  {
  	return -1;			//ошибка
  }
}

Там где не справляется функция GetParamHTML, работает функция GetParamHTMLv2. Подробно останавливаться на последней не будем. Она является менее чувствительной к закрывающемуся тэгу и применяется для парсинга сайта американской почты.

Не знаю, почему так сложилось, но не люблю я кодировку UTF-8. Как оказалось некоторые провайдеры, предоставляющие услуги SMS рассылок, работают только с русскоязычной кодировкой WIN CP-1251, а сайт Российской почты выдает данные в кодировке UTF-8. Для согласования кодировок в модуль function.php добавлена функция UTFtoCP1251 ($str,$type). Где $str – строка для преобразования, $type –конечная кодировка («w» – WIN CP-1251, «u» – UTF-8).

Еще раз повторюсь, что для каждой страны предполагается наличие своего модуля, содержащего только одну функцию. Так модуль usps.php содержит функцию GetUSATrackData, которая в качестве аргумента требует только трек американской почты. После вызова функция вернет двумерный массив (в случае успешного выполнения) либо -1 (если номер не зарегистрирован в почтовой системе).

Простейший пример, позволяющий распечатать информацию об отслеживании с американского сайта USPS, приведен в следующем куске кода.

Исходный код
<?
include_once "function.php";
include_once "usps.php";
$datas=GetUSATrackData('CJ462051684US');
if ($datas==-1)
{
  echo 'Данные об отправлении устарели либо недоступны';
  exit;
}
for ($x=0;$x<count($datas);$x++)
{
  for ($y=0;$y<count($datas[$x]);$y++)
  {
    echo $datas[$x][$y].';';
  }
  echo '<br>';
}
?>

Аналогично работает функция GetRussiaTrackData из модуля rupost.php. Для отслеживания посылок в Гонконге разработана функция GetHonKongTrackData (модуль hkpost.php), для Китая – GetChinaTrackData (модуль chinapost.php). Обращаю внимание, что последние две функции возвращают одномерный массив, содержащий лишь текущее состояние посылки.

Чтобы описанный код обрел значимость и полезность необходим еще один модуль, назовем его условно main_task.php. Для полноценной работы алгоритма нам понадобится 2 таблицы MySQL:

1. Таблица rupost. Сюда мы будем заносить информацию с почтовых серверов.
Структура таблицы rupost
ПолеТипСравнениеNullДополнительноОсобые параметры
Idbigint(20)Нетauto_incrementКлючевое поле
trackvarchar(14)cp1251_general_ciНет
operationvarchar(255)cp1251_general_ciНет
dateopdatetimeНет
postalcodevarchar(7)cp1251_general_ciНет
nameopsvarchar(255)cp1251_general_ciНет
atribvarchar(255)cp1251_general_ciНет
weightvarchar(10)cp1251_general_ciНет
money_valvarchar(10)cp1251_general_ciНет
money_payvarchar(10)cp1251_general_ciНет
postal_adrvarchar(7)cp1251_general_ciНет
adressvarchar(255)cp1251_general_ciНет
posttypevarchar(1)cp1251_general_ciНет

2. Таблица task, содержащая перечень номеров для отслеживания.
Структура таблицы task
ПолеТипСравнениеNullДополнительноОсобые параметры
Idbigint(20)Нетauto_incrementКлючевое поле
tracknumbervarchar(14)cp1251_general_ciНет

Разберемся теперь, как работает алгоритм. Из таблицы task циклически считываются номера, запрос о состоянии которых посылается первым делом на сайт русской почты, а затем, в случае неудачи, на адреса международных почтовых служб. После каждого удачного запроса формируется строка, которая посредством MySQL сравнивается со значениями таблицы rupost. Если новые данные в таблице отсутствуют, то они дописываются в rupost, и формируется SMS сообщение об изменении статуса посылки. В случае если при очередном запросе новых данных (об одном отправлении) оказалось больше чем строчка, то в SMS сообщении придет лишь последняя.

Файл main_task.php требует предварительной настройки. Необходимо инициализировать значения следующих переменных:

$dblogin="user";            	//Имя пользователя для доступа к БД MYSQL
$dbpassword="password";     	//Пароль для доступа к БД MySQL
$dbsqlname="basename";      	//Имя базы данных MYSQL
$phone="+79020000004";      	//Телефон на который будут отсылаться SMS

Оператором для отправки SMS через интернет я выбрал службу SMSC.RU, поэтому требуется занести данные своего аккаунта в файл smsc_api.php.

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

В заключении хочется сказать, что весь материал предназначен лишь для ознакомления. Использование наработок в коммерческих целях строго запрещено. Перепечатка материалов возможна только с моего разрешения и с соблюдением ссылок на первоисточник. Желающих поддержать не только словом, но и делом, а также поблагодарить – прошу ко мне на почту.

Файлы из статьи можно скачать здесь.

Удачи в Ваших начинаниях!!!