├── composer.json
├── samples
└── example.php
├── src
├── RussianPostCODRecord.php
├── RussianPostTrackingRecord.php
└── RussianPostAPI.php
└── README.md
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "injapan/russianpost",
3 | "description": "Russian Post API",
4 | "require": {
5 | "php": ">=5.0.0"
6 | },
7 | "autoload": {
8 | "psr-0": {
9 | "": "src/"
10 | }
11 | },
12 | "minimum-stability": "stable"
13 | }
--------------------------------------------------------------------------------
/samples/example.php:
--------------------------------------------------------------------------------
1 | getOperationHistory('42382396002056', 'RUS')); //Use 'ENG' for English
10 |
11 | //fetch COD payment info
12 | var_dump($client->getCODHistory('42382396002056', 'RUS'));
13 | } catch(RussianPostException $e) {
14 | die('Something went wrong: ' . $e->getMessage() . "\n");
15 | }
--------------------------------------------------------------------------------
/src/RussianPostCODRecord.php:
--------------------------------------------------------------------------------
1 | 5.0 с включенными модулями:
49 | - pcre
50 | - curl
51 | - SimpleXML
52 |
53 |
54 | Russian Post items tracking via PHP
55 | ===================================
56 |
57 | **Changelog**
58 |
59 | - *2015-04-22* COD payment information; composer compatibility
60 | - *2012-11-24* First release
61 |
62 | **Install**
63 |
64 | Add custom repo and package requirement to composer.json:
65 |
66 | ```javascript
67 | {
68 | "repositories": [
69 | {
70 | "type": "vcs",
71 | "url": "https://github.com/InJapan/russianpost-tracking"
72 | }
73 | ],
74 | "require": {
75 | "injapan/russianpost": "dev-master"
76 | }
77 | }
78 | ```
79 |
80 | Run composer install.
81 |
82 | **Access**
83 |
84 | Web service used by the library does not require authentication of the requests.
85 | However you're required to obtain authorization for it's usage by mailing freeformed request to fc@russianpost.ru.
86 |
87 | **Usage**
88 |
89 | See example.php
90 |
91 | **Dependencies**
92 |
93 | PHP >5.0 is required with following extensions enabled:
94 | - pcre
95 | - curl
96 | - SimpleXML
97 |
--------------------------------------------------------------------------------
/src/RussianPostAPI.php:
--------------------------------------------------------------------------------
1 |
5 | *
6 | ************************************************************************
7 | * You MUST request usage access for this API through request mailed to *
8 | * fc@russianpost.ru *
9 | ************************************************************************
10 | *
11 | * This program is free software: you can redistribute it and/or modify
12 | * it under the terms of the GNU General Public License as published by
13 | * the Free Software Foundation, either version 3 of the License, or
14 | * (at your option) any later version.
15 | *
16 | * This program is distributed in the hope that it will be useful,
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 | * GNU General Public License for more details.
20 | *
21 | * You should have received a copy of the GNU General Public License
22 | * along with this program. If not, see .
23 | */
24 |
25 | class RussianPostAPI {
26 | /**
27 | * SOAP service URL
28 | */
29 | const SOAPEndpoint = 'http://voh.russianpost.ru:8080/niips-operationhistory-web/OperationHistory';
30 |
31 | const SOAPUser = 'admin';
32 | const SOAPPassword = 'adminadmin'; //LOL
33 |
34 | protected $proxyHost;
35 | protected $proxyPort;
36 | protected $proxyAuthUser;
37 | protected $proxyAuthPassword;
38 |
39 | /**
40 | * Constructor. Pass proxy config here.
41 | * @param string $proxyHost
42 | * @param string $proxyPort
43 | * @param string $proxyAuthUser
44 | * @param string $proxyAuthPassword
45 | */
46 | public function __construct($proxyHost = "", $proxyPort = "", $proxyAuthUser = "", $proxyAuthPassword = "") {
47 | $russianpostRequiredExtensions = array('SimpleXML', 'curl', 'pcre');
48 | foreach($russianpostRequiredExtensions as $russianpostExt) {
49 | if (!extension_loaded($russianpostExt)) {
50 | throw new RussianPostSystemException('Required extension ' . $russianpostExt . ' is missing', 100);
51 | }
52 | }
53 |
54 | $this->proxyHost = $proxyHost;
55 | $this->proxyPort = $proxyPort;
56 | $this->proxyAuthUser = $proxyAuthUser;
57 | $this->proxyAuthPassword = $proxyAuthPassword;
58 | }
59 |
60 | /**
61 | * Returns tracking data
62 | * @param string $trackingNumber tracking number
63 | * @param string $language language for output strings
64 | * @return array of RussianPostTrackingRecord
65 | */
66 | public function getOperationHistory($trackingNumber, $language = 'RUS') {
67 | $trackingNumber = $this->checkTrackingNumber($trackingNumber);
68 |
69 | $message = <<
71 |
72 |
73 |
74 | $trackingNumber
75 | 0
76 | $language
77 |
78 |
79 |
80 | EOD;
81 |
82 | $data = $this->makeRequest($message);
83 | $data = $this->parseResponse($data);
84 |
85 | $records = $data->OperationHistoryData->historyRecord;
86 |
87 | if (empty($records))
88 | throw new RussianPostDataException("There is no tracking data in XML response", 101);
89 |
90 | $out = array();
91 | foreach($records as $rec) {
92 | $outRecord = new RussianPostTrackingRecord();
93 | $outRecord->operationType = (string) $rec->OperationParameters->OperType->Name;
94 | $outRecord->operationTypeId = (int) $rec->OperationParameters->OperType->Id;
95 |
96 | $outRecord->operationAttribute = (string) $rec->OperationParameters->OperAttr->Name;
97 | $outRecord->operationAttributeId = (int) $rec->OperationParameters->OperAttr->Id;
98 |
99 | $outRecord->operationPlacePostalCode = (string) $rec->AddressParameters->OperationAddress->Index;
100 | $outRecord->operationPlaceName = (string) $rec->AddressParameters->OperationAddress->Description;
101 |
102 | $outRecord->destinationPostalCode = (string) $rec->AddressParameters->DestinationAddress->Index;
103 | $outRecord->destinationAddress = (string) $rec->AddressParameters->DestinationAddress->Description;
104 |
105 | $outRecord->operationDate = (string) $rec->OperationParameters->OperDate;
106 |
107 | $outRecord->itemWeight = round(floatval($rec->ItemParameters->Mass) / 1000, 3);
108 | $outRecord->declaredValue = floatval($rec->FinanceParameters->Value);
109 | $outRecord->collectOnDeliveryPrice = floatval($rec->FinanceParameters->Payment);
110 |
111 | $out[] = $outRecord;
112 | }
113 |
114 | return $out;
115 | }
116 |
117 | /**
118 | * Returns cash-on-delivery payment data
119 | * @param string $trackingNumber tracking number
120 | * @param string $language language for output strings
121 | * @return array of RussianPostCODRecord
122 | */
123 | public function getCODHistory($trackingNumber, $language = 'RUS') {
124 | $trackingNumber = $this->checkTrackingNumber($trackingNumber);
125 |
126 | $user = self::SOAPUser;
127 | $pass = self::SOAPPassword;
128 |
129 | $message = <<
131 |
132 |
133 | $user
134 | $pass
135 |
136 |
137 |
138 |
139 |
140 |
141 | EOD;
142 |
143 | $data = $this->makeRequest($message);
144 | $data = $this->parseResponse($data);
145 |
146 | $records = $data->PostalOrderEventsForMaiOutput;
147 |
148 | if (empty($records))
149 | throw new RussianPostDataException("There is no COD data in XML response", 102);
150 |
151 | $out = array();
152 | foreach($records->children() as $rec) {
153 | $rec = $rec->attributes();
154 |
155 | $outRecord = new RussianPostCODRecord();
156 |
157 | $outRecord->paymentNumber = (int) $rec->Number;
158 | $outRecord->eventDate = (string) $rec->EventDateTime;
159 | $outRecord->eventTypeId = (int) $rec->EventType;
160 | $outRecord->eventName = (string) $rec->EventName;
161 | $outRecord->destinationPostalCode = (string) $rec->IndexTo;
162 | $outRecord->eventPostalCode = (string) $rec->IndexEvent;
163 | $outRecord->paymentAmount = round(intval($rec->SumPaymentForward) / 100, 2);
164 | $outRecord->destinationContryCode = (string) $rec->CountryToCode;
165 | $outRecord->eventCountryCode = (string) $rec->CountryEventCode;
166 |
167 | $out[] = $outRecord;
168 | }
169 |
170 | return $out;
171 | }
172 |
173 | protected function checkTrackingNumber($trackingNumber) {
174 | $trackingNumber = trim($trackingNumber);
175 | if (!preg_match('/^[0-9]{14}|[A-Z]{2}[0-9]{9}[A-Z]{2}$/', $trackingNumber)) {
176 | throw new RussianPostArgumentException('Incorrect format of tracking number: ' . $trackingNumber, 103);
177 | }
178 |
179 | return $trackingNumber;
180 | }
181 |
182 | protected function parseResponse($raw) {
183 | $xml = @simplexml_load_string($raw);
184 |
185 | if (!is_object($xml))
186 | throw new RussianPostDataException("Failed to parse XML response", 104);
187 |
188 | $ns = $xml->getNamespaces(true);
189 |
190 | foreach($ns as $key => $dummy) {
191 | if (strpos($key, 'ns') === 0) {
192 | $nsKey = $key;
193 | break;
194 | }
195 | }
196 |
197 | if (empty($nsKey)) {
198 | throw new RussianPostDataException("Failed to detect correct namespace in XML response", 105);
199 | }
200 |
201 | if (!(
202 | $xml->children($ns['S'])->Body &&
203 | $data = $xml->children($ns['S'])->Body->children($ns[$nsKey])
204 | ))
205 | throw new RussianPostDataException("There is no tracking data in XML response", 106);
206 |
207 | return $data;
208 | }
209 |
210 | protected function makeRequest($message) {
211 | $channel = curl_init(self::SOAPEndpoint);
212 |
213 | curl_setopt_array($channel, array(
214 | CURLOPT_POST => true,
215 | CURLOPT_RETURNTRANSFER => true,
216 | CURLOPT_CONNECTTIMEOUT => 10,
217 | CURLOPT_TIMEOUT => 10,
218 | CURLOPT_POSTFIELDS => $message,
219 | CURLOPT_HTTPHEADER => array(
220 | 'Content-Type: text/xml; charset=utf-8',
221 | 'SOAPAction: ""',
222 | ),
223 | ));
224 |
225 | if (!empty($this->proxyHost) && !empty($this->proxyPort)) {
226 | curl_setopt($channel, CURLOPT_PROXY, $this->proxyHost . ':' . $this->proxyPort);
227 | }
228 |
229 | if (!empty($this->proxyAuthUser)) {
230 | curl_setopt($channel, CURLOPT_PROXYUSERPWD, $this->proxyAuthUser . ':' . $this->proxyAuthPassword);
231 | }
232 |
233 | $result = curl_exec($channel);
234 | if ($errorCode = curl_errno($channel)) {
235 | throw new RussianPostChannelException(curl_error($channel), $errorCode);
236 | }
237 |
238 | return $result;
239 | }
240 | }
241 |
242 | class RussianPostException extends Exception { }
243 | class RussianPostArgumentException extends RussianPostException { }
244 | class RussianPostSystemException extends RussianPostException { }
245 | class RussianPostChannelException extends RussianPostException { }
246 | class RussianPostDataException extends RussianPostException { }
--------------------------------------------------------------------------------