PageRenderTime 56ms CodeModel.GetById 28ms RepoModel.GetById 0ms app.codeStats 0ms

/src/htdocs/plugins/class.ib.avangard.php

https://github.com/aig/ofx
PHP | 229 lines | 152 code | 48 blank | 29 comment | 15 complexity | 132776ce268f3367386301131d98645c MD5 | raw file
  1. <?php
  2. /*
  3. * Copyright (c) AIG
  4. * aignospam at gmail.com
  5. *
  6. * Redistribution and use in source and binary forms, with or without
  7. * modification, are permitted provided that the following conditions
  8. * are met:
  9. * 1. Redistributions of source code must retain the above copyright
  10. * notice, this list of conditions and the following disclaimer.
  11. * 2. Redistributions in binary form must reproduce the above copyright
  12. * notice, this list of conditions and the following disclaimer in the
  13. * documentation and/or other materials provided with the distribution.
  14. *
  15. * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  16. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  17. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  18. * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
  19. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  20. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  21. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  22. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  23. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  24. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  25. * SUCH DAMAGE.
  26. */
  27. class IB_AVANGARD extends IB
  28. {
  29. private $_account_list;
  30. private $_main_page;
  31. function __construct() {
  32. parent::__construct("avangard");
  33. $this->_account_list = null;
  34. }
  35. function login($user, $fish) {
  36. // try to log in.
  37. $result = $this->curlLogin($user, $fish);
  38. if (!$result) return false;
  39. if (!preg_match('/window.location="(faces\/pages\/firstpage\?ticket=.*?)"/', $result, $match)) {
  40. return false;
  41. }
  42. // fetch main IB page.
  43. $result = $this->curlMain($match[1]);
  44. $this->_main_page = iconv('cp1251', 'utf-8', html_entity_decode($result, ENT_COMPAT, 'cp1251'));
  45. $this->_account_list = array();
  46. if (preg_match_all('/>((?:40817|42307|42306)\d{3}\d{12})/', $this->_main_page, $matches)) {
  47. foreach ($matches[1] as $account_id) {
  48. $this->_account_list[] = new BankAccount($account_id);
  49. }
  50. }
  51. return true;
  52. }
  53. private function getStateToken($page) {
  54. if (preg_match('/name="oracle\.adf\.faces\.STATE_TOKEN"\s+value="(\d+)"/', $page, $match)) {
  55. return $match[1];
  56. }
  57. return false;
  58. }
  59. public function getAccountBalance($account_id, $inctran = false) {
  60. if (!preg_match('/'
  61. . $account_id
  62. . '.*?"Детальная информация по счету".*?submitForm\(\'f\'\,1\,\{source:\'(.*?)\'\}\).*?"Выписка по счету"/', $this->_main_page, $action_match))
  63. {
  64. throw new Exception("Unknown bank account: $account_id");
  65. }
  66. $source = $action_match[1];
  67. $state_token = $this->getStateToken($this->_main_page);
  68. $ch = curl_init();
  69. curl_setopt($ch, CURLOPT_URL, "https://www.avangard.ru/ibAvn/faces/pages/accounts/all_acc.jspx");
  70. curl_setopt($ch, CURLOPT_POST, 1);
  71. curl_setopt($ch, CURLOPT_POSTFIELDS, "oracle.adf.faces.FORM=f&"
  72. ."oracle.adf.faces.STATE_TOKEN=$state_token&"
  73. ."source=" . urlencode($source));
  74. $result = $this->curlExec($ch);
  75. $page = iconv('cp1251', 'utf-8', html_entity_decode($result, ENT_COMPAT, 'cp1251'));
  76. if (!preg_match('/'
  77. . $account_id
  78. . '<\/label><\/td><td class="x2p x62"><span style="display:none;">\-?[\d\s]+.\d+<\/span><div><\/div>'
  79. . '<label for="f:leftAccTbl:0:selLeftAcc">\s*(\-?[\d\s]+.\d+)</', $page, $match))
  80. {
  81. return false;
  82. }
  83. $info = array();
  84. $info['balance'] = preg_replace("/\s/", '', $match[1]);
  85. if (empty($inctran)) {
  86. return $info;
  87. }
  88. // GnuCash does not set <INCTRAN> INCLUDE field to N, when check balance
  89. if ($inctran == '19700101') {
  90. return $info;
  91. }
  92. $start_date = strftime('%d.%m.%Y', strtotime("$inctran" . "000000"));
  93. if (!preg_match('/name="f:finishdate" value="(\d+\.\d+\.\d+)"/', $page, $match)) {
  94. return $info;
  95. }
  96. $finish_date = $match[1];
  97. $regexp = '/' . $account_id . '.*?submitForm\(\\\\\'f\\\\\'\,1\,\{source:\\\\\'(.*?)\\\\\'\}\).*?"Показать"/s';
  98. if (!preg_match($regexp, $page, $match)) {
  99. return $info;
  100. }
  101. $source = urlencode($match[1]);
  102. $state_token = $this->getStateToken($page);
  103. $fields = "f%3Astartdate=$start_date&"
  104. ."f%3Afinishdate=$finish_date&"
  105. ."f%3AleftAccTbl%3Aselected=0&"
  106. ."f%3AleftAccTbl%3ArangeStart=0&"
  107. ."f%3AleftCardTbl%3A_us=0&"
  108. ."f%3AleftCardTbl%3A_us=1&"
  109. ."f%3AleftCardTbl%3ArangeStart=0&"
  110. ."oracle.adf.faces.FORM=f&oracle.adf.faces.STATE_TOKEN=$state_token&"
  111. ."source=$source&"
  112. ."event=&"
  113. ."f%3AleftCardTbl%3A_sm=";
  114. $ch = curl_init();
  115. curl_setopt($ch, CURLOPT_URL, "https://www.avangard.ru/ibAvn/faces/pages/accounts/acc_stat.jspx");
  116. curl_setopt($ch, CURLOPT_POST, 1);
  117. curl_setopt($ch, CURLOPT_POSTFIELDS, $fields);
  118. $result = $this->curlExec($ch);
  119. $page = iconv('cp1251', 'utf-8', html_entity_decode($result, ENT_COMPAT, 'cp1251'));
  120. $info['trn_list'] = $this->parseTransactionList($page);
  121. return $info;
  122. }
  123. private function parseTransactionList($page) {
  124. $transaction_list = array();
  125. if (!preg_match('/ПРОВЕДЕННЫЕ ПО КАРТСЧЕТУ ОПЕРАЦИИ(.*?)Исходящий остаток средств на картсчете/s', $page, $match)) {
  126. return $transaction_list;
  127. }
  128. // $1: date, $2: ammount, $3: tr_datetime, $4: tr_card, $5: tr_amount, $6: currency, $7: tr_description
  129. $regexp = '/(\d{2}\.\d{2}\.\d{4})\s*<\/td>\s*<td[^>]+>\s*<\/td>.*?([\d ]+\.\d+).*?Покупка.*?(\d{2}\.\d{2}\.\d{4}\s\d{2}:\d{2}:\d{2}).*?Карта.*?\*(\d{4})\..*?Сумма.*?([\d ]+\.\d+).*?>(...)\..*?>Место\s([^<]+)/s';
  130. if (preg_match_all($regexp, $match[1], $matches)) {
  131. for ($i = 0; $i < count($matches[0]); $i++) {
  132. $transaction = array();
  133. $transaction['trntype'] = 'POS';
  134. $transaction['dtposted'] = substr($matches[1][$i], 6, 4)
  135. . substr($matches[1][$i], 3, 2)
  136. . substr($matches[1][$i], 0, 2);
  137. $transaction['trnamt'] = '-' . preg_replace('/\s/', '', $matches[2][$i]);
  138. $transaction['card'] = $matches[4][$i];
  139. $transaction['orgamount'] = preg_replace('/\s/', '', $matches[5][$i]);
  140. $transaction['fitid'] = md5($matches[1][$i].$matches[2][$i].$matches[3][$i].$matches[4][$i].$matches[6][$i].$matches[7][$i]);
  141. $transaction['dtuser'] = $matches[3][$i];
  142. $transaction['origcurrency'] = $matches[6][$i];
  143. $transaction['name'] = $matches[7][$i];
  144. $transaction_list[] = $transaction;
  145. }
  146. }
  147. return $transaction_list;
  148. }
  149. function getAccountList() {
  150. return $this->_account_list;
  151. }
  152. private function curlLogin($user, $fish) {
  153. $ch = curl_init();
  154. curl_setopt($ch, CURLOPT_URL, "http://www.avangard.ru/rus/index.wbp");
  155. $result = $this->curlExec($ch);
  156. if (!preg_match('/<INPUT\s+value="login"\s+name="([^\"]+)"/i', $result, $match)) {
  157. return false;
  158. }
  159. $login_name = $match[1];
  160. $password = decryptPassword($user, CONFIG::getValue('ib.avangard', 'user.password'), $fish);
  161. $ch = curl_init();
  162. curl_setopt($ch, CURLOPT_URL, "https://www.avangard.ru/client4/afterlogin");
  163. curl_setopt($ch, CURLOPT_POST, 1);
  164. curl_setopt($ch, CURLOPT_POSTFIELDS, "$login_name=login&"
  165. ."65783213-C4EC-46C3-AEF5-172B7C75C400.redirect=%2Frus%2Findex.wbp&"
  166. ."login_v=&"
  167. ."login=$user&"
  168. ."passwd_v=&"
  169. ."passwd=$password&"
  170. ."x=20&y=7");
  171. $result = $this->curlExec($ch);
  172. return $result;
  173. }
  174. private function curlMain($url) {
  175. $ch = curl_init();
  176. curl_setopt($ch, CURLOPT_URL, "https://www.avangard.ru/ibAvn/" . $url);
  177. $result = $this->curlExec($ch);
  178. return $result;
  179. }
  180. }
  181. ?>