├── .gitattributes ├── .gitignore ├── LICENSE.txt ├── LICENSE_BOL.txt ├── LICENSE_GNU_AGPLv3.txt ├── LICENSE_GNU_APL.txt ├── README.txt ├── client.inc ├── client.php ├── client ├── 202.html ├── 403.html ├── 503.html ├── 511.html ├── btn_1.gif ├── btn_2.gif ├── btn_3.gif ├── btn_4.gif ├── btn_5.gif ├── debug.html ├── form.html ├── home.html ├── icon.ico ├── icon.png ├── rule.css ├── template.html ├── template.js └── wsofx.gif ├── common.inc ├── common ├── fi.xml └── ofx.xml ├── index.php ├── index.txt ├── log └── .gitkeep ├── php.ini ├── php_mac.ini ├── server.inc ├── server.php ├── server ├── auwallet.inc ├── benefit401k.inc ├── btmu.inc ├── chocom.inc ├── dccard.inc ├── esaifu.inc ├── jaccscard.inc ├── jist.inc ├── jpbank.inc ├── kabucom.inc ├── mhbk.inc ├── mobilesuica.inc ├── mufgcard.inc ├── nanaco.inc ├── netbk.inc ├── nrkn.inc ├── osaifuponta.inc ├── rakutensec.inc ├── saisoncard.inc ├── sbisec.inc ├── smbc.inc ├── smbccard.inc ├── smcprepaide.inc ├── surugavisacard.inc ├── viewcard.inc └── waon.inc └── start_php.bat /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | 19 | *.bat eol=crlf 20 | *.ini eol=crlf 21 | *.xml eol=crlf 22 | 23 | *.inc linguist-language=PHP 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Project ignored files 2 | log/*.log 3 | 4 | # Windows image file caches 5 | Thumbs.db 6 | ehthumbs.db 7 | 8 | # Folder config file 9 | Desktop.ini 10 | 11 | # Recycle Bin used on file shares 12 | $RECYCLE.BIN/ 13 | 14 | # Windows Installer files 15 | *.cab 16 | *.msi 17 | *.msm 18 | *.msp 19 | 20 | # Windows shortcuts 21 | *.lnk 22 | 23 | # ========================= 24 | # Operating System Files 25 | # ========================= 26 | 27 | # OSX 28 | # ========================= 29 | 30 | .DS_Store 31 | .AppleDouble 32 | .LSOverride 33 | 34 | # Thumbnails 35 | ._* 36 | 37 | # Files that might appear on external disk 38 | .Spotlight-V100 39 | .Trashes 40 | 41 | # Directories potentially created on remote AFP share 42 | .AppleDB 43 | .AppleDesktop 44 | Network Trash Folder 45 | Temporary Items 46 | .apdisk 47 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | OFXProxyは、GNU AFFERO GENERAL PUBLIC LICENSE Version 3、および 2 | Beatrek Origin Licenseのデュアルライセンスに基づき提供いたします。 3 | 4 | ライセンスの詳細については、./LICENSE_GNU_AGPLv3.txt、および./LICENSE_BOL.txtを 5 | ご参照ください。 6 | 7 | 8 | ./server.*, ./server/*.*:, ./client.*, ./client/*.*: 9 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 10 | 上記ファイルは、GNU AFFERO GENERAL PUBLIC LICENSE Version 3、および 11 | Beatrek Origin Licenseのデュアルライセンスに基づき提供いたします。 12 | 13 | ライセンスの詳細については、./LICENSE_GNU_AGPLv3.txt、および./LICENSE_BOL.txtを 14 | ご参照ください。 15 | 16 | 17 | ./common.*, ./common/*.*, ./index.*, ./README.txt, ./php*.ini, ./start_php.bat: 18 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 19 | 上記ファイルは、GNU All-Permissive License、およびBeatrek Origin Licenseの 20 | デュアルライセンスに基づき提供いたします。 21 | 22 | ライセンスの詳細については、./LICENSE_GNU_APL.txt、および./LICENSE_BOL.txtを 23 | ご参照ください。 24 | 25 | -------------------------------------------------------------------------------- /LICENSE_BOL.txt: -------------------------------------------------------------------------------- 1 | Beatrek Origin License 2 | 3 | (準拠法) 4 | 本ライセンスの解釈、および適用は、日本国法に準拠するものとします。 5 | 6 | (著作権) 7 | 本ライセンスが適用されるソースコードの著作権は、特に記載のない限り、 8 | 著作者であるアウター・ガイ事務所に帰属するものであり、日本国著作権法、 9 | 国際条約、およびその他の法律によって保護されています。 10 | 明示的に付与されていないすべての権利は、著作者により留保されています。 11 | 12 | (適用の除外) 13 | 本ライセンスが適用されるソースコードのうち、アウター・ガイ事務所以外の 14 | 者が著作者であるソースコード部分については、本ライセンスが適用されない 15 | ものとします。 16 | 17 | (使用、および利用の制限) 18 | 本ライセンスが適用されるソースコードは、著作者が何らの制約を受ける 19 | ことなく、著作者の自己の技術を他に転用する目的で、現状有姿のまま 20 | 供するものであり、お客様が事前に著作者の文書による許諾を得た場合を 21 | 除き、かかる目的、あるいはその他法律によって明示的に認められる範囲を 22 | 超えて、かかるソースコードを、いかなる方法によっても使用、および利用 23 | することはできません。 24 | 25 | (免責) 26 | 著作者は、本ライセンスが適用されるソースコードに関して、明示的、 27 | あるいは黙示的を問わず、一切保証しません。 28 | 著作者は、本ライセンスが適用されるソースコードの使用、または 29 | 使用不能により生じたあらゆる損失および損害について、著作者が予見し、 30 | または予見し得た場合を含め、いかなる場合も一切責任を負わないものと 31 | します。 32 | 33 | -------------------------------------------------------------------------------- /LICENSE_GNU_APL.txt: -------------------------------------------------------------------------------- 1 | GNU All-Permissive License 2 | 3 | Copying and distribution of this file, with or without modification, 4 | are permitted in any medium without royalty provided the copyright 5 | notice and this notice are preserved. This file is offered as-is, 6 | without any warranty. 7 | 8 | -------------------------------------------------------------------------------- /README.txt: -------------------------------------------------------------------------------- 1 | OFXProxy:対応金融機関のOFXファイルをダウンロードするサービス 2 | 3 | OFXProxyは、対応金融機関の口座情報をOFXファイルとしてダウンロードできるサービスです。取得した明細データは、OFX対応ソフト・サービスに取り込めます。 4 | 5 | OFXProxyを実行するには、PHPバージョン5.4以降が必要です。 6 | 7 | ソースコード(GitHub) 8 | https://github.com/outerguy/ofxproxy 9 | 10 | プロジェクトサイト(Beatrek) 11 | https://www.beatrek.com/home/ofxproxy.htm 12 | 13 | Beatrek OFX仕様書(Beatrek) 14 | https://www.beatrek.com/home/ofxspec.htm 15 | 16 | -------------------------------------------------------------------------------- /client.inc: -------------------------------------------------------------------------------- 1 | ", "", "", ""), array($fi["fiid"], $fi["name"], $fi["home"], trim(get_auth($fi))), $str); 30 | } 31 | return $ret; 32 | } 33 | 34 | // 認証情報を生成する 35 | function get_auth($fi) { 36 | $ret = ""; 37 | 38 | $forms = explode("|", $fi["form"]); 39 | foreach($forms as $form) { 40 | list($text, $attr) = explode("|", $fi[$form], 2); 41 | $attr = strtolower($attr); 42 | switch($attr) { 43 | case "text": 44 | case "password": 45 | break; 46 | default: 47 | $attr = "text"; 48 | break; 49 | } 50 | $ret .= "
" . $text . "
\r\n"; 51 | $ret .= "
\r\n"; 52 | } 53 | 54 | return $ret; 55 | } 56 | 57 | // 金融機関一覧を生成する 58 | function get_filist($fis) { 59 | $ret = ""; 60 | 61 | foreach($fis as $fi) $ret .= "
  • \r\n"; 62 | 63 | return $ret; 64 | } 65 | 66 | ?> 67 | -------------------------------------------------------------------------------- /client.php: -------------------------------------------------------------------------------- 1 | ", "", "", "\"\""), array(ENV_PRODUCT_CLIENT_VERSION, ENV_PRODUCT_VERSION, ENV_PRODUCT_FAMILY, (ENV_BOOL_DEBUG == true? "true": "false")), $js); 17 | 18 | // レスポンスを返す 19 | header(get_http_status(ENV_NUM_STATUS_SUCCESS)); 20 | header("Cache-Control: no-cache"); 21 | header("Pragma: no-cache"); 22 | header("Content-Type: text/javascript; charset=UTF-8"); 23 | header("Content-Length: " . strlen($js)); 24 | echo $js; 25 | 26 | ?> 27 | -------------------------------------------------------------------------------- /client/202.html: -------------------------------------------------------------------------------- 1 |

    追加認証

    2 |

    本人確認のため、より追加認証を求められています。

    3 | 4 |

    5 |
    6 |
    7 |
    追加認証
    8 |
    9 |
    10 |
    11 |
    12 |
    We Support OFXロゴ中止するヘルプ
    13 |
    14 | -------------------------------------------------------------------------------- /client/403.html: -------------------------------------------------------------------------------- 1 |

    認証エラー

    2 |

    ログインできませんでした。

    3 |

    認証情報の内容を確認した後、再試行してください。

    4 | 5 |
    6 |

    7 |

    8 |
    9 | 10 |
    11 | 12 |
    13 | -------------------------------------------------------------------------------- /client/503.html: -------------------------------------------------------------------------------- 1 |

    メンテナンスエラー

    2 |

    システムメンテナンス画面が表示されたため、処理を中断しました。

    3 |

    のシステムメンテナンスが終了した後、再試行してください。

    4 | 5 |
    6 |

    7 |

    8 |
    9 | 10 |
    11 | 12 |
    13 | -------------------------------------------------------------------------------- /client/511.html: -------------------------------------------------------------------------------- 1 |

    情報取得エラー

    2 |

    「重要なお知らせ」等の画面が表示されたため、処理を中断しました。

    3 |

    にログインし、画面を確認した後、再試行してください。

    4 | 5 |
    6 |

    7 |

    8 |
    9 | 10 |
    11 | 12 |
    13 | -------------------------------------------------------------------------------- /client/btn_1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/outerguy/ofxproxy/89e0d8a08537897d628bc46ddf862452d39ee2df/client/btn_1.gif -------------------------------------------------------------------------------- /client/btn_2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/outerguy/ofxproxy/89e0d8a08537897d628bc46ddf862452d39ee2df/client/btn_2.gif -------------------------------------------------------------------------------- /client/btn_3.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/outerguy/ofxproxy/89e0d8a08537897d628bc46ddf862452d39ee2df/client/btn_3.gif -------------------------------------------------------------------------------- /client/btn_4.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/outerguy/ofxproxy/89e0d8a08537897d628bc46ddf862452d39ee2df/client/btn_4.gif -------------------------------------------------------------------------------- /client/btn_5.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/outerguy/ofxproxy/89e0d8a08537897d628bc46ddf862452d39ee2df/client/btn_5.gif -------------------------------------------------------------------------------- /client/debug.html: -------------------------------------------------------------------------------- 1 |

    【警告】開発者向け(デバッグ)機能が有効のため、認証情報を含む詳細な記録が残ります。開発者以外の方は、操作しないでください。または、開発者へご相談ください。

    2 | -------------------------------------------------------------------------------- /client/form.html: -------------------------------------------------------------------------------- 1 |
    2 |

    3 |
    4 |
    5 | 6 |
    7 |
    We Support OFXロゴヘルプ
    8 |
    9 |
    10 | -------------------------------------------------------------------------------- /client/home.html: -------------------------------------------------------------------------------- 1 |

    We Support OFX

    2 |

    OFXProxyは、対応金融機関の口座情報をOFXファイルとしてダウンロードできるサービスです。生成した電子明細をOFX対応マネー管理ソフトに取り込めます。

    3 |

    金融機関の非表示設定は、最大60日間、Cookieに保持されます。

    4 | 12 |

    銀行

    13 | 14 |

    クレジットカード

    15 | 16 |

    証券

    17 | 18 |

    前払式帳票

    19 | 20 |

    金融機関の非表示設定

    21 | 24 |
    25 | 29 |

    30 |
    31 |

    バージョン情報

    32 |
    33 |

    ブラウザーのJavaScriptが無効になっているため、表示できません。

    34 |
    35 | -------------------------------------------------------------------------------- /client/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/outerguy/ofxproxy/89e0d8a08537897d628bc46ddf862452d39ee2df/client/icon.ico -------------------------------------------------------------------------------- /client/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/outerguy/ofxproxy/89e0d8a08537897d628bc46ddf862452d39ee2df/client/icon.png -------------------------------------------------------------------------------- /client/rule.css: -------------------------------------------------------------------------------- 1 | * { 2 | font-family: "メイリオ", "Meiryo", sans-serif; 3 | } 4 | body { 5 | width: 720px; 6 | border: 0px; 7 | padding: 0px; 8 | margin: 20px; 9 | color: #000000; 10 | background: #FFFFFF; 11 | cursor: default; 12 | } 13 | h1 { 14 | margin: 0px; 15 | color: #993300; 16 | background: transparent; 17 | } 18 | h2 { 19 | border: solid #993300; 20 | border-width: 0px 0px 2px 0px; 21 | margin: 1em 0px 0px 0px; 22 | color: #993300; 23 | background: transparent; 24 | } 25 | h3 { 26 | border: solid #FF9900; 27 | border-width: 2px 2px 0px 2px; 28 | margin: 1em 0px 0px 0px; 29 | color: #FFFFFF; 30 | background: #FF9900; 31 | text-indent: 0.5em; 32 | text-align: center; 33 | clear: both; 34 | } 35 | h3 a { 36 | color: #FFFFFF; 37 | background: transparent; 38 | } 39 | h4 { 40 | margin: 1em 0px 0px 0px; 41 | color: #CC6600; 42 | background: transparent; 43 | } 44 | p { 45 | margin: 0px; 46 | } 47 | p#debug { 48 | border: 0px; 49 | padding: 0.5em; 50 | margin: 0px; 51 | color: #FFFFFF; 52 | background: #FF0000; 53 | font-weight: bold; 54 | } 55 | p#wsofx { 56 | float: right; 57 | clear: right; 58 | } 59 | p.product { 60 | border: 0px; 61 | padding: 0px; 62 | margin: 8px 0px 0px 0px; 63 | font-weight: bold; 64 | } 65 | p.product a { 66 | border: 0px; 67 | padding: 0px; 68 | margin: 0px 8px 0px 0px; 69 | } 70 | div#addmsg { 71 | display: none; 72 | } 73 | code { 74 | color: #333333; 75 | background: transparent; 76 | font-family: monospace; 77 | line-height: 110%; 78 | } 79 | form.ofxform { 80 | border: solid 2px #FF9900; 81 | border-radius: 0px 0px 10px 10px; 82 | padding: 0px 0px 5px 0px; 83 | margin: 0px; 84 | color: #CC6600; 85 | background: #FFFFCC; 86 | } 87 | form.ofxform dl { 88 | padding: 0px 10px 0px 10px; 89 | } 90 | form.ofxform dt { 91 | float: left; 92 | clear: both; 93 | width: 160px; 94 | padding: 0.1em 0px 0.1em 0px; 95 | font-size: 80%; 96 | text-align: left; 97 | } 98 | form.ofxform dt:after { 99 | content: ":"; 100 | } 101 | form.ofxform dd { 102 | margin-left: 160px; 103 | padding: 0.1em 0px 0.1em 10px; 104 | color: #000000; 105 | background: transparent; 106 | } 107 | form.ofxform dd input.ofxinput { 108 | width: 180px; 109 | } 110 | form.ofxform div.ofximage { 111 | float: right; 112 | position: relative; 113 | top: -45px; 114 | left: -10px; 115 | width: 320px; 116 | height: 40px; 117 | } 118 | form.ofxform div.ofximage input { 119 | cursor: pointer; 120 | } 121 | a img { 122 | border: 0px; 123 | } 124 | -------------------------------------------------------------------------------- /client/template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | OFXProxy 19 | 20 | 21 | 22 | 23 | 24 |

    OFXProxy

    25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /client/template.js: -------------------------------------------------------------------------------- 1 | /* 2 | template.js: 画面・機能を制御する 3 | Copyright (C) 2012-2015 OFFICE OUTERGUY. All rights reserved. 4 | mailto:contact@beatrek.com 5 | Dual-licensed under the GNU AGPLv3 and Beatrek Origin License. 6 | */ 7 | 8 | // グローバル変数・定数を定義する 9 | var debug = ""; 10 | var ver = "."; 11 | var family = ""; 12 | var flag_ofxform = false; 13 | 14 | (function() { 15 | // 起動時にロード機能を呼び出す 16 | with(self.window) if(addEventListener) { 17 | addEventListener("load", fnc_load, true); 18 | } else if(attachEvent) { 19 | attachEvent("onload", fnc_load); 20 | } else { 21 | onload = fnc_load; 22 | } 23 | 24 | // Cookieを読み込む 25 | load_cookie_ofxform(); 26 | 27 | // Cookieを書き込む 28 | save_cookie_ofxform(); 29 | 30 | })(); 31 | 32 | 33 | // ========================================================================= 34 | // 機能 35 | // ========================================================================= 36 | 37 | // ロード機能 38 | function fnc_load() { 39 | // バージョン情報を表示する 40 | var cdf = document.createDocumentFragment(); 41 | var tag_body = dom_get_tag("body")[0]; 42 | var title = dom_get_tag("title")[0].firstChild.nodeValue; 43 | var tag_div = dom_get_id("ver"); 44 | var tag_p, tag_a; 45 | 46 | tag_p = dom_create_tag("p", { "class": "product" }); 47 | tag_a = dom_create_tag("a", { "href": "https://github.com/outerguy/ofxproxy", "target": "_blank" }); 48 | tag_a.appendChild(dom_create_text(title)); 49 | tag_p.appendChild(tag_a); 50 | tag_p.appendChild(dom_create_text("Version " + ver)); 51 | cdf.appendChild(tag_p); 52 | 53 | tag_p = dom_create_tag("p"); 54 | tag_p.appendChild(dom_create_text("Copyright (C) 2008-2015 OFFICE OUTERGUY. All rights reserved.")); 55 | cdf.appendChild(tag_p); 56 | 57 | tag_p = dom_create_tag("p"); 58 | tag_p.appendChild(dom_create_text("Portions Copyright (C) 2012-2015 Hiromu2000. All rights reserved.")); 59 | cdf.appendChild(tag_p); 60 | 61 | if(tag_div != null) with(tag_div) { 62 | while(hasChildNodes() == true) removeChild(lastChild); 63 | appendChild(cdf); 64 | } 65 | 66 | return; 67 | } 68 | 69 | function exec_ofxform(obj) { 70 | var ret = false; 71 | var fnc = function() { 72 | flag_ofxform = false; 73 | 74 | return; 75 | }; 76 | with(obj) { 77 | if(flag_ofxform == true) { 78 | alert("明細のダウンロードを開始するまで、しばらくお待ちください。"); 79 | } else { 80 | self.window.setTimeout(fnc, 2000); 81 | flag_ofxform = true; 82 | ret = true; 83 | } 84 | } 85 | 86 | return ret; 87 | } 88 | 89 | function link_ofxform(obj) { 90 | with(obj) target = parentNode.id; 91 | 92 | return true; 93 | } 94 | 95 | function help_ofxform(obj) { 96 | obj.target = "help_ofxform"; 97 | 98 | return true; 99 | } 100 | 101 | function load_cookie_ofxform() { 102 | var cookies = self.document.cookie.split("; "); 103 | var i; 104 | for(i = 0; i < cookies.length; i++) { 105 | kvs = cookies[i].split("=", 2); 106 | if(dom_get_id(kvs[0])) { 107 | dom_get_id(kvs[0]).style.display = kvs[1]; 108 | dom_get_id(kvs[0] + "_hide").checked = (kvs[1] == "none"? true: false); 109 | } 110 | } 111 | 112 | return; 113 | } 114 | 115 | function save_cookie_ofxform() { 116 | var tag_inputs = dom_get_tag("input"); 117 | var expire = new Date(); 118 | var i; 119 | 120 | expire.setTime(expire.getTime() + 86400000 * 60); 121 | 122 | for(i in tag_inputs) with(tag_inputs[i]) if(typeof type != "undefined" && type == "checkbox" && id != "all_hide") { 123 | self.document.cookie = id.replace("_hide", "") + "=" + (checked == true? "none": "block") + "; expires=" + expire.toUTCString(); 124 | } 125 | 126 | return; 127 | } 128 | 129 | 130 | // ========================================================================= 131 | // 関数 132 | // ========================================================================= 133 | 134 | // DOMよりタグに合致するエレメントを取得する 135 | function dom_get_tag(name) { 136 | var obj = null; 137 | 138 | with(self.document) if(typeof getElementsByTagName != "undefined") try { 139 | if(typeof name == "string") obj = getElementsByTagName(name); 140 | } catch(e) { 141 | void(e); 142 | } 143 | 144 | return obj; 145 | } 146 | 147 | // DOMよりIDに合致するエレメントを取得する 148 | function dom_get_id(name) { 149 | var obj = null; 150 | 151 | with(self.document) if(typeof getElementById != "undefined") try { 152 | if(typeof name == "string") obj = getElementById(name); 153 | } catch(e) { 154 | void(e); 155 | } 156 | 157 | return obj; 158 | } 159 | 160 | // DOMのテキストを生成する 161 | function dom_create_text(text) { 162 | var obj = null; 163 | 164 | with(self.document) if(typeof createTextNode != "undefined") try { 165 | if(typeof text == "string") obj = createTextNode(dom_convert_escape(text)); 166 | } catch(e) { 167 | void(e); 168 | } 169 | 170 | return obj; 171 | } 172 | 173 | // DOMのタグを生成する 174 | function dom_create_tag(name, attrs) { 175 | var obj = null; 176 | var i; 177 | 178 | with(self.document) if(typeof createElement != "undefined") try { 179 | if(typeof name == "string") obj = createElement(name); 180 | } catch(e) { 181 | void(e); 182 | } 183 | 184 | if(typeof attrs != "array") for(i in attrs) try { 185 | obj.setAttribute(i, dom_convert_escape(attrs[i])); 186 | } catch(e) { 187 | void(e); 188 | } 189 | 190 | return obj; 191 | } 192 | 193 | // DOMの特定文字をエスケープする 194 | function dom_convert_escape(str) { 195 | var ret = ""; 196 | var buf = ""; 197 | var hcs = { "amp": "&", "quot": "\"", "lt": "<", "gt": ">" }; 198 | var fnc; 199 | var i; 200 | 201 | if(str.indexOf(hcs["amp"]) == -1) { 202 | ret = str; 203 | } else { 204 | fnc = function() { 205 | return hcs[arguments[1]]; 206 | }; 207 | 208 | for(i in hcs) buf += "|" + i; 209 | ret = str.replace(new RegExp(hcs["amp"] + "(" + buf.substring(1) + ");", "g"), fnc); 210 | } 211 | 212 | return ret; 213 | } 214 | -------------------------------------------------------------------------------- /client/wsofx.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/outerguy/ofxproxy/89e0d8a08537897d628bc46ddf862452d39ee2df/client/wsofx.gif -------------------------------------------------------------------------------- /common.inc: -------------------------------------------------------------------------------- 1 | fi as $fi) { 36 | $id = mb_htmlspecialchars((string)$fi["id"]); 37 | $settings[$id]["fiid"] = mb_htmlspecialchars((string)$id); 38 | $settings[$id]["type"] = mb_htmlspecialchars((string)$fi->type); 39 | $settings[$id]["name"] = mb_htmlspecialchars((string)$fi->name); 40 | $settings[$id]["home"] = mb_htmlspecialchars((string)$fi->home); 41 | if(isset($fi["code"]) == true) $settings[$id]["code"] = mb_htmlspecialchars((string)$fi["code"]); 42 | if(isset($fi->additional) == true) $settings[$id]["additional"] = mb_htmlspecialchars(implode("|", array((string)$fi->additional, (string)$fi->additional["input"], (string)$fi->additional["type"]))); 43 | if(isset($fi->help) == true) $settings[$id]["help"] = preg_replace("/^[\r\n]*([\w\W]*?)<\/help>[\r\n]*$/", "\\1", $fi->help->asXML()); 44 | 45 | $inputs = array(); 46 | foreach($fi->form->input as $input) { 47 | array_push($inputs, mb_htmlspecialchars((string)$input["id"])); 48 | $settings[$id][(string)$input["id"]] = mb_htmlspecialchars(implode("|", array((string)$input, (string)$input["type"]))); 49 | } 50 | $settings[$id]["form"] = implode("|", $inputs); 51 | 52 | if(isset($fi->itemlist) == true) foreach($fi->itemlist->item as $item) $settings[$id][(string)$item["id"]] = mb_htmlspecialchars((string)$item); 53 | } 54 | 55 | $ret = ($fiid != "" && isset($settings[$fiid]) == true? $settings[$fiid]: $settings); 56 | 57 | return $ret; 58 | } 59 | 60 | function mb_htmlspecialchars($str) { 61 | return htmlspecialchars($str, ENT_COMPAT | ENT_XML1, "UTF-8"); 62 | } 63 | 64 | // $codeに合致するHTTP/1.1ステータスコードの文字列を取得する 65 | function get_http_status($code) { 66 | $status = "Unknown Status-code"; 67 | switch((integer)$code) { 68 | // 100 69 | case 100: 70 | $status = "Continue"; 71 | break; 72 | case 101: 73 | $status = "Switching Protocols"; 74 | break; 75 | case 102: 76 | $status = "Processing"; 77 | break; 78 | // 200 79 | case 200: 80 | $status = "OK"; 81 | break; 82 | case 201: 83 | $status = "Created"; 84 | break; 85 | case 202: 86 | $status = "Accepted"; 87 | break; 88 | case 203: 89 | $status = "Non-Authoritative Information"; 90 | break; 91 | case 204: 92 | $status = "No Content"; 93 | break; 94 | case 205: 95 | $status = "Reset Content"; 96 | break; 97 | case 206: 98 | $status = "Partial Content"; 99 | break; 100 | case 207: 101 | $status = "Multi-Status"; 102 | break; 103 | case 208: 104 | $status = "Already Reported"; 105 | break; 106 | case 226: 107 | $status = "IM Used"; 108 | break; 109 | // 300 110 | case 300: 111 | $status = "Multiple Choices"; 112 | break; 113 | case 301: 114 | $status = "Moved Parmanently"; 115 | break; 116 | case 302: 117 | $status = "Found"; 118 | break; 119 | case 303: 120 | $status = "See Other"; 121 | break; 122 | case 304: 123 | $status = "Not Modified"; 124 | break; 125 | case 305: 126 | $status = "Use Proxy"; 127 | break; 128 | case 306: 129 | $status = "(Unused)"; 130 | break; 131 | case 307: 132 | $status = "Temporary Redirect"; 133 | break; 134 | case 308: 135 | $status = "Permanent Redirect"; 136 | break; 137 | // 400 138 | case 400: 139 | $status = "Bad Request"; 140 | break; 141 | case 401: 142 | $status = "Unautorized"; 143 | break; 144 | case 402: 145 | $status = "Payment Required"; 146 | break; 147 | case 403: 148 | $status = "Forbidden"; 149 | break; 150 | case 404: 151 | $status = "Not Found"; 152 | break; 153 | case 405: 154 | $status = "Method Not Allowed"; 155 | break; 156 | case 406: 157 | $status = "Not Acceptable"; 158 | break; 159 | case 407: 160 | $status = "Proxy Authentication Required"; 161 | break; 162 | case 408: 163 | $status = "Request Timeout"; 164 | break; 165 | case 409: 166 | $status = "Conflict"; 167 | break; 168 | case 410: 169 | $status = "Gone"; 170 | break; 171 | case 411: 172 | $status = "Length Required"; 173 | break; 174 | case 412: 175 | $status = "Precondition Failed"; 176 | break; 177 | case 413: 178 | $status = "Request Entity Too Large"; 179 | break; 180 | case 414: 181 | $status = "Request-URI Too Long"; 182 | break; 183 | case 415: 184 | $status = "Unsupported Media Type"; 185 | break; 186 | case 416: 187 | $status = "Requested Range Not Satisfiable"; 188 | break; 189 | case 417: 190 | $status = "Expectation Failed"; 191 | break; 192 | case 422: 193 | $status = "Unprocessable Entity"; 194 | break; 195 | case 423: 196 | $status = "Locked"; 197 | break; 198 | case 424: 199 | $status = "Failed Dependency"; 200 | break; 201 | case 426: 202 | $status = "Upgrade Required"; 203 | break; 204 | case 428: 205 | $status = "Precondition Required"; 206 | break; 207 | case 429: 208 | $status = "Too Many Requests"; 209 | break; 210 | case 431: 211 | $status = "Request Header Fields Too Large"; 212 | break; 213 | // 500 214 | case 500: 215 | $status = "Internal Server Error"; 216 | break; 217 | case 501: 218 | $status = "Not Implemented"; 219 | break; 220 | case 502: 221 | $status = "Bad Gateway"; 222 | break; 223 | case 503: 224 | $status = "Service Unavailable"; 225 | break; 226 | case 504: 227 | $status = "Gateway Timeout"; 228 | break; 229 | case 505: 230 | $status = "HTTP Version Not Supported"; 231 | break; 232 | case 506: 233 | $status = "Variant Also Negotiates"; 234 | break; 235 | case 507: 236 | $status = "Insufficient Storage"; 237 | break; 238 | case 508: 239 | $status = "Loop Detected"; 240 | break; 241 | case 510: 242 | $status = "Not Extended"; 243 | break; 244 | case 511: 245 | $status = "Network Authentication Required"; 246 | break; 247 | default: 248 | // 何もしない 249 | break; 250 | } 251 | return "HTTP/1.1 " . (string)$code . " " . $status; 252 | } 253 | 254 | ?> 255 | -------------------------------------------------------------------------------- /common/ofx.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 14 | 15 | 0INFOJPN 16 | 17 | 18 | -------------------------------------------------------------------------------- /index.php: -------------------------------------------------------------------------------- 1 | ヘルプ\r\n"; 48 | $str .= "

    " . $fis[$fiid]["name"] . "

    \r\n"; 49 | $str .= str_replace("h3", "h4", $fis[$fiid]["help"]); 50 | $str .= "

    \r\n"; 51 | } else { 52 | // デバッグ機能が有効の場合、デバッグHTMLを取得する 53 | if(ENV_BOOL_DEBUG == true) $str .= file_get_contents(ENV_FILE_DIR_CLIENT . ENV_FILE_TEMPLATE_DEBUG); 54 | 55 | // ホームHTMLを取得する 56 | $str .= file_get_contents(ENV_FILE_DIR_CLIENT . ENV_FILE_TEMPLATE_HOME); 57 | 58 | // 埋め込み文字列を置換する 59 | $str = str_replace(array("", "", "", "", ""), array(trim(get_form($banks)), trim(get_form($creditcards)), trim(get_form($invstmts)), trim(get_form($prepaids)), trim(get_filist($fis))), $str); 60 | } 61 | 62 | $html = str_replace("", trim($str), $html); 63 | 64 | // レスポンスを返す 65 | header(get_http_status(ENV_NUM_STATUS_SUCCESS)); 66 | header("Cache-Control: no-cache"); 67 | header("Pragma: no-cache"); 68 | header("Content-Type: text/html; charset=UTF-8"); 69 | header("Content-Length: " . strlen($html)); 70 | echo $html; 71 | 72 | ?> 73 | -------------------------------------------------------------------------------- /index.txt: -------------------------------------------------------------------------------- 1 | PHP関数インデックス 2 | 3 | ■(boolean)env_dlog((string)$html, (string)$tag) 4 | 【説明】 5 | ENV_BOOL_DEBUGがtrueの場合、デバッグログを出力する。 6 | 7 | ■(array)get_fi_settings((string)$fiid = "") { 8 | 【説明】 9 | XMLファイルより$fiidセクションの定義を取得する。 10 | 11 | ■(string)mb_htmlspecialchars((string)$str) 12 | 【説明】 13 | 特殊文字をXHTMLエンティティーを変換する。 14 | 15 | ■(string)sess_encode((string)$str) 16 | 【説明】 17 | $strよりセッション保持用文字列を作成する。 18 | 19 | ■(string)sess_decode((string)$str) 20 | 【説明】 21 | セッション保持用文字列($str)より元データを取得する。 22 | 23 | ■(string)mb_convert_uniqueid((string)$str) 24 | 【説明】 25 | $strより32バイトの一意な文字列を生成する。 26 | 27 | ■(string)mb_convert_uniquename((string)$str) 28 | 【説明】 29 | 文字列を正規化する。 30 | 31 | ■(string)mb_convert_string((string)$str) 32 | 【説明】 33 | 文字エンコーディングをShift_JISからUTF-8へと変換する。 34 | 35 | ■class ofxDOM 36 | Copyright (C) 2012-2017 Hiromu Takahashi All Rights Reserved. 37 | mailto:hiromu2000@hotmail.com 38 | 39 | ■(string)parse_amount((string)$str) 40 | 【説明】 41 | 金額をパースする。 42 | 43 | ■(string)parse_date((string)$str) 44 | 【説明】 45 | 日付をパースする。 46 | 47 | ■(string)parse_param((string)$str) 48 | 【説明】 49 | フォーム経由で送受信されるパラメータをパースする。 50 | ※urlencode()やurldecode()で変換されない文字列も変換する。 51 | 52 | ■(array)parse_tag((string)$html, (string)$tag, (boolean)$recursive) 53 | 【説明】 54 | 指定された開始タグから終了タグまでのHTML、およびタグの属性を取得する。 55 | $recursiveがtrueの場合、タグの入れ子内部も再帰的に取得する。 56 | 【例】 57 | $html = "" . "
    "; 58 | $tag = "select"; 59 | parse_tag($html, $tag) = array(2) { 60 | [0]=> 61 | array(3) { 62 | ["name"]=> 63 | string(3) "abc" 64 | ["class"]=> 65 | string(1) "x" 66 | ["innerHTML"]=> 67 | string(76) "" 68 | } 69 | [1]=> 70 | array(3) { 71 | ["name"]=> 72 | string(3) "def" 73 | ["class"]=> 74 | string(1) "Y" 75 | ["innerHTML"]=> 76 | string(73) "" 77 | } 78 | } 79 | 80 | ■(array)parse_tag_attributes((string)$html, (string)$tag) 81 | 【説明】 82 | 指定されたタグの属性を取得する。 83 | 【例】 84 | $html = "" . ""; 85 | $tag = "input"; 86 | parse_tag_attributes($html, $tag) = array(2) { 87 | [0]=> 88 | array(3) { 89 | ["type"]=> 90 | string(4) "text" 91 | ["name"]=> 92 | string(3) "abc" 93 | ["value"]=> 94 | string(0) "" 95 | } 96 | [1]=> 97 | array(3) { 98 | ["type"]=> 99 | string(6) "HIDDEN" 100 | ["name"]=> 101 | string(3) "def" 102 | ["value"]=> 103 | string(3) "xyz" 104 | } 105 | } 106 | 107 | ■(integer)parse_tag_search((array)$tags, (string)$key, (string)$value) 108 | 【説明】 109 | 指定されたタグ配列より属性が一致($key=$value)するタグの配列番号を取得する。 110 | 【例】 111 | $tags = array(); 112 | $tags[0] = array("type" => "text", "name" => "abc", "value" => "", "innerHTML" => ""); 113 | $tags[1] = array("type" => "hidden", "name" => "def", "value" => "xyz", "innerHTML" => ""); 114 | $key = "name"; 115 | $value = "def"; 116 | parse_tag_search($tags, $key, $value) = int(1) 117 | 118 | ■(array)parse_header((string)$http, (string)$head) 119 | 【説明】 120 | $headに一致するHTTPヘッダーの配列を取得する。 121 | 122 | ■(array)parse_uri((string)$uri_next, (array)$uris = array()) 123 | 【説明】 124 | $uri_nextを$urisからの絶対・相対パスURIとしてパースする。 125 | PHPの標準関数parse_url()と異なり、クエリーは"query"ではなく、"path"に含めて返却する。 126 | 【例】 127 | $uri_next = "../global.html?lang=en"; 128 | $uris = array(); 129 | $uris["scheme"] = "http"; 130 | $uris["host"] = "www.example.com"; 131 | $uris["path"] = "/japan/index.html"; 132 | parse_uri($uri_next, $uris) = array(3) { 133 | ["scheme"]=> 134 | string(4) "http" 135 | ["host"]=> 136 | string(15) "www.example.com" 137 | ["path"]=> 138 | string(19) "/global.html?lang=en" 139 | } 140 | 141 | ■(array)parse_csv((string)$csv, (string)$delimiter = ",", (string)$enclosure = "\"") 142 | 【説明】 143 | CSV形式のデータをパースする。 144 | 145 | ■(string)http11((string)$method, (string)$protocol, (string)$host, (integer)$port = 0, (string)$page = "/", (string)$query = "", (string)$basic = "", (string)$cookie = "", (boolean)$autoconv = true, (string)$ua = ENV_PRODUCT_UA, (string)$fr = "", (string)$referer = "") 146 | 【説明】 147 | HTTP/1.1プロトコルでアクセスする。 148 | 149 | ■(string)http11_fread_blocking((resource)$fp, (integer)$len) 150 | 【説明】 151 | Chunkedのデータをfreadで読み込みする際、指定サイズ未満しか取得できない場合があるのを改善する。 152 | 153 | ■(string)update_cookie((array)$memories, (array)$heads, (string)$cookie) 154 | 【説明】 155 | $memoriesに存在するキーを$headsより探し、$cookieの値を更新する。 156 | 157 | ■(string)convert_ofx((string)$ofx) 158 | 【説明】 159 | OFX 1.0.2からOFX 2.1.1へと整形する。 160 | 161 | ■(string)generate_ofx((string)$status, (string)$str = ENV_STR_OFX_NODATA, (string)$cook = "", (string)$akey = "") 162 | 【説明】 163 | テンプレートよりOFX 2.1.1を生成する。 164 | 165 | ■(string)generate_html((string)$settings, (array)$resp) 166 | 【説明】 167 | テンプレートよりHTMLを生成する。 168 | 169 | ■(string)get_http_status((integer)$code) 170 | 【説明】 171 | $codeに合致するHTTP/1.1ステータスコードの文字列を取得する。 172 | 173 | -------------------------------------------------------------------------------- /log/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/outerguy/ofxproxy/89e0d8a08537897d628bc46ddf862452d39ee2df/log/.gitkeep -------------------------------------------------------------------------------- /php.ini: -------------------------------------------------------------------------------- 1 | [PHP] 2 | extension_dir = ".\ext"; 3 | extension=php_mbstring.dll 4 | extension=php_openssl.dll 5 | 6 | [Date] 7 | date.timezone = "Asia/Tokyo" 8 | -------------------------------------------------------------------------------- /php_mac.ini: -------------------------------------------------------------------------------- 1 | [Date] 2 | date.timezone = "Asia/Tokyo" 3 | -------------------------------------------------------------------------------- /server.php: -------------------------------------------------------------------------------- 1 | 0) { 86 | header("Content-Length: " . (string)$n); 87 | echo $content; 88 | } 89 | 90 | ?> 91 | -------------------------------------------------------------------------------- /server/chocom.inc: -------------------------------------------------------------------------------- 1 | 0) { 32 | $method = "GET"; 33 | $uris = parse_uri($locations[0], $uris); 34 | $query = ""; 35 | $cookie = chocom_update_cookie($head, $cookie); 36 | list($head, $body) = chocom_http11($method, $uris, $query, $cookie); 37 | } 38 | } 39 | 40 | // ログイン画面を取得する 41 | $as = parse_tag($body, "a"); 42 | foreach($as as $a) if(parse_tag_search(parse_tag($a["innerHTML"], "img"), "alt", "会員ログイン") != -1) { 43 | $method = "GET"; 44 | $uris = parse_uri($a["href"], $uris); 45 | $query = ""; 46 | $cookie = chocom_update_cookie($head, $cookie); 47 | list($head, $body) = chocom_http11($method, $uris, $query, $cookie); 48 | break; 49 | } 50 | 51 | // リダイレクトする 52 | $scripts = parse_tag($body, "script"); 53 | foreach($scripts as $script) if(preg_match("/location\.replace\(\'(.*?)\'/i", $script["innerHTML"], $matches) > 0) { 54 | $method = "GET"; 55 | $uris = parse_uri($matches[1], $uris); 56 | $query = ""; 57 | $cookie = chocom_update_cookie($head, $cookie); 58 | list($head, $body) = chocom_http11($method, $uris, $query, $cookie); 59 | break; 60 | } 61 | 62 | // ログインする 63 | $forms = parse_tag($body, "form"); 64 | $c = parse_tag_search($forms, "name", "form1"); 65 | if($c != -1) { 66 | $inputs = parse_tag($forms[$c]["innerHTML"], "input"); 67 | $queries = array(); 68 | foreach($inputs as $input) if($input["name"] != "") $queries[$input["name"]] = urlencode($input["name"]) . "=" . urlencode($input["value"]); 69 | $queries["MAILADDR"] = "MAILADDR=" . $user; 70 | $queries["TELEPHONE"] = "TELEPHONE=" . $tel; 71 | $queries["PASSWORD"] = "PASSWORD=" . $pass; 72 | 73 | $method = $forms[$c]["method"]; 74 | $uris = parse_uri($forms[$c]["action"], $uris); 75 | $query = implode("&", $queries); 76 | $cookie = chocom_update_cookie($head, $cookie); 77 | list($head, $body) = chocom_http11($method, $uris, $query, $cookie); 78 | } 79 | 80 | if(strpos($body, "ログインすることが出来ませんでした") !== false) { 81 | // システムメンテナンス画面の場合 82 | $resp["status"] = ENV_NUM_STATUS_MAINTENANCE; 83 | $resp["method"] = $method; 84 | $resp["uri"] = $uris["scheme"] . "://" . $uris["host"] . $uris["path"]; 85 | $resp["query"] = $query; 86 | $resp["cookie"] = $cookie; 87 | $resp["head"] = $head; 88 | $resp["body"] = $body; 89 | $resp["ofx"] = generate_ofx($resp["status"]); 90 | } else if(strpos($body, "ご利用履歴") === false) { 91 | // ログイン失敗の場合 92 | $resp["status"] = ENV_NUM_STATUS_FAILURE; 93 | $resp["method"] = $method; 94 | $resp["uri"] = $uris["scheme"] . "://" . $uris["host"] . $uris["path"]; 95 | $resp["query"] = $query; 96 | $resp["cookie"] = $cookie; 97 | $resp["head"] = $head; 98 | $resp["body"] = $body; 99 | $resp["ofx"] = generate_ofx($resp["status"]); 100 | } else { 101 | // ログアウト画面を退避する 102 | $forms = parse_tag($body, "form"); 103 | $c = parse_tag_search($forms, "name", "clickChecker"); 104 | if($c != -1) { 105 | $inputs = parse_tag($forms[$c]["innerHTML"], "input"); 106 | $queries = array(); 107 | foreach($inputs as $input) if($input["name"] != "") $queries[$input["name"]] = urlencode($input["name"]) . "=" . urlencode($input["value"]); 108 | $queries["clickCounter"] = "clickCounter=1"; 109 | 110 | $method_old = $forms[$c]["method"]; 111 | $uris_old = parse_uri($forms[$c]["action"], $uris); 112 | $query_old = implode("&", $queries); 113 | } 114 | 115 | $account = array(); 116 | 117 | $account["acctname"] = $settings["name"] . ENV_CHR_CONCATENATOR . $user; 118 | 119 | // 支店番号を取得する 120 | if(preg_match("/" . preg_quote("貯金箱番号") . "[\s\t]*([0-9]+)/", $body, $matches) > 0) $account["branchid"] = $matches[1]; 121 | 122 | // 口座番号を取得する 123 | if(preg_match("/\.Com\-ID[\s\t]*([0-9]{4}\-[0-9]{4}\-[0-9]{4}\-[0-9]{4}\-[0-9]{4}\-[0-9])/", $body, $matches) > 0) $account["acctid"] = str_replace("-", "", $matches[1]); 124 | 125 | // 残高を取得する 126 | if(preg_match("/" . preg_quote("貯金箱残高") . "[\s\t]*:[\s\t]*([0-9]+)/", $body, $matches) > 0) $account["balance"] = parse_amount($matches[1]); 127 | 128 | // 履歴残高照会画面を取得する 129 | $as = parse_tag($body, "a"); 130 | $c = parse_tag_search($as, "innerHTML", "履歴照会"); 131 | if($c != -1) { 132 | $method = "GET"; 133 | $uris = parse_uri($as[$c]["href"], $uris); 134 | $query = ""; 135 | $cookie = chocom_update_cookie($head, $cookie); 136 | list($head, $body) = chocom_http11($method, $uris, $query, $cookie, false); // 文字コードを変換しない 137 | } 138 | 139 | // 履歴表示画面(1ページ目)を取得する 140 | $forms = parse_tag($body, "form"); 141 | $c = parse_tag_search($forms, "name", "sForm"); 142 | if($c != -1) { 143 | $queries = array(); 144 | $inputs = parse_tag($forms[$c]["innerHTML"], "input"); 145 | foreach($inputs as $input) if($input["name"] != "") $queries[$input["name"]] = urlencode($input["name"]) . "=" . urlencode($input["value"]); 146 | $selects = parse_tag($forms[$c]["innerHTML"], "select"); 147 | foreach($selects as $select) { 148 | $options = parse_tag($select["innerHTML"], "option"); 149 | foreach($options as $option) if($select["name"] != "" && $option["selected"] == "selected") $queries[$select["name"]] = urlencode($select["name"]) . "=" . urlencode($option["value"]); 150 | } 151 | $queries["yearStart"] = "yearStart=" . (string)(integer)substr(ENV_STR_DATE_PASTDAY, 0, 4); 152 | $queries["monthStart"] = "monthStart=" . (string)(integer)substr(ENV_STR_DATE_PASTDAY, 4, 2); 153 | $queries["dayStart"] = "dayStart=" . (string)(integer)substr(ENV_STR_DATE_PASTDAY, 6, 2); 154 | $queries["yearFinish"] = "yearFinish=" . (string)(integer)substr(ENV_STR_DATE_TODAY, 0, 4); 155 | $queries["monthFinish"] = "monthFinish=" . (string)(integer)substr(ENV_STR_DATE_TODAY, 4, 2); 156 | $queries["dayFinish"] = "dayFinish=" . (string)(integer)substr(ENV_STR_DATE_TODAY, 6, 2); 157 | 158 | $method = $forms[$c]["method"]; 159 | $uris = parse_uri($forms[$c]["action"], $uris); 160 | $query = implode("&", $queries); 161 | $cookie = chocom_update_cookie($head, $cookie); 162 | list($head, $body) = chocom_http11($method, $uris, $query, $cookie, false); // 文字コードを変換しない 163 | } 164 | 165 | $account["details"] = chocom_get_details($body); 166 | 167 | // 履歴表示画面(2ページ目以降)を取得する 168 | while(parse_tag_search(parse_tag($body, "a"), "innerHTML", "以前の履歴") != -1) { 169 | $forms = parse_tag($body, "form"); 170 | $c = parse_tag_search($forms, "name", "hisForm"); 171 | if($c != -1) { 172 | $inputs = parse_tag($forms[$c]["innerHTML"], "input"); 173 | $queries = array(); 174 | foreach($inputs as $input) { 175 | switch($input["name"]) { 176 | case "": 177 | // 何もしない 178 | break; 179 | case "E2BURL": 180 | $forms[$c]["action"] = $input["value"]; 181 | // breakしない 182 | default: 183 | $queries[$input["name"]] = urlencode($input["name"]) . "=" . urlencode($input["value"]); 184 | break; 185 | } 186 | } 187 | $queries["REQ_PAGE"] = "REQ_PAGE=NEXT"; 188 | 189 | $method = $forms[$c]["method"]; 190 | $uris = parse_uri($forms[$c]["action"], $uris); 191 | $query = implode("&", $queries); 192 | $cookie = chocom_update_cookie($head, $cookie); 193 | list($head, $body) = chocom_http11($method, $uris, $query, $cookie, false); // 文字コードを変換しない 194 | 195 | $account["details"] = array_merge(chocom_get_details($body), $account["details"]); 196 | } 197 | } 198 | 199 | // 実行時間(タイムアウト)を再設定する 200 | @set_time_limit(ENV_NUM_TIMEOUT); 201 | 202 | // ログアウトする 203 | $method = $method_old; 204 | $uris = $uris_old; 205 | $query = $query_old; 206 | $cookie = chocom_update_cookie($head, $cookie); 207 | list($head, $body) = chocom_http11($method, $uris, $query, $cookie); 208 | 209 | // リダイレクトする 210 | $retry = 0; 211 | while($retry++ < ENV_NUM_HTTP11_RETRY) { 212 | $locations = parse_header($head, "location"); 213 | if(count($locations) > 0) { 214 | $method = "GET"; 215 | $uris = parse_uri($locations[0], $uris); 216 | $query = ""; 217 | $cookie = chocom_update_cookie($head, $cookie); 218 | list($head, $body) = chocom_http11($method, $uris, $query, $cookie); 219 | } 220 | } 221 | 222 | // 実行時間(タイムアウト)を再設定する 223 | @set_time_limit(ENV_NUM_TIMEOUT); 224 | 225 | $bankmsgsrsv1 = ""; 226 | $bankmsgsrsv1 .= ""; 227 | $bankmsgsrsv1 .= "\r\n"; 228 | 229 | // 口座情報を取得する 230 | $bankmsgsrsv1 .= ""; 231 | $bankmsgsrsv1 .= "\r\n"; 232 | $bankmsgsrsv1 .= "0"; 233 | $bankmsgsrsv1 .= "\r\n"; 234 | $bankmsgsrsv1 .= "0INFO"; 235 | $bankmsgsrsv1 .= "\r\n"; 236 | $bankmsgsrsv1 .= ""; 237 | $bankmsgsrsv1 .= "\r\n"; 238 | $bankmsgsrsv1 .= "" . ENV_STR_OFX_CURRENCY_JPY . ""; 239 | $bankmsgsrsv1 .= "\r\n"; 240 | $bankmsgsrsv1 .= ""; 241 | $bankmsgsrsv1 .= "" . $settings["code"] . ""; 242 | $bankmsgsrsv1 .= "" . $account["branchid"] . ""; 243 | $bankmsgsrsv1 .= "" . $account["acctid"] . ""; 244 | $bankmsgsrsv1 .= "" . ENV_STR_ACCTTYPE_CHECKING . ""; 245 | $bankmsgsrsv1 .= ""; 246 | $bankmsgsrsv1 .= "\r\n"; 247 | $bankmsgsrsv1 .= chocom_parse_details($account); 248 | $bankmsgsrsv1 .= ""; 249 | $bankmsgsrsv1 .= "\r\n"; 250 | $bankmsgsrsv1 .= ""; 251 | $bankmsgsrsv1 .= "\r\n"; 252 | 253 | $bankmsgsrsv1 .= ""; 254 | $bankmsgsrsv1 .= "\r\n"; 255 | 256 | // OFXファイルを出力する 257 | $resp["status"] = ENV_NUM_STATUS_SUCCESS; 258 | $resp["ofx"] = generate_ofx($resp["status"], $bankmsgsrsv1); 259 | } 260 | return $resp; 261 | 262 | // HTTP/1.1 263 | function chocom_http11($method, $uris, $query = "", $cookie = "", $autoconv = true) { 264 | $ret = "INVALID HOST"; 265 | if(preg_match("/\.chocom\.(?:jp|net)$/", $uris["host"]) > 0) $ret = http11(strtoupper($method), $uris["scheme"], $uris["host"], 0, $uris["path"], $query, "", $cookie, $autoconv); 266 | return explode("\r\n\r\n", $ret, 2); 267 | } 268 | 269 | function chocom_update_cookie($head, $cookie) { 270 | return update_cookie(array("AlteonP", "JSESSIONID"), parse_header($head, "set-cookie"), $cookie); 271 | } 272 | 273 | function chocom_get_details($body) { 274 | $rets = array(); 275 | $i = 0; 276 | $trs = parse_tag(mb_convert_string($body), "tr"); 277 | foreach($trs as $tr) { 278 | $tds = parse_tag($tr["innerHTML"], "td"); 279 | if(count($tds) == 6) { 280 | // 利用日付を取得する 281 | $rets[$i]["date"] = parse_date(trim(strip_tags($tds[0]["innerHTML"]))); 282 | 283 | // ご利用先を取得する 284 | $name1 = str_replace(" ", "", trim(strip_tags($tds[1]["innerHTML"]))); 285 | $name2 = str_replace(" ", "", trim(strip_tags($tds[3]["innerHTML"]))); 286 | $rets[$i]["summary"] = ($name1 == "" || $name2 == ""? $name1 . $name2: implode(ENV_CHR_CONCATENATOR, array($name1, $name2))); 287 | 288 | // ご利用金額を取得する 289 | $rets[$i]["amount"] = parse_amount($tds[4]["innerHTML"]); 290 | 291 | $i++; 292 | } 293 | } 294 | 295 | return $rets; 296 | } 297 | 298 | function chocom_parse_details($account) { 299 | $ret = ""; 300 | $cds = array(); 301 | $cd_date = ""; 302 | $cd_num = 0; 303 | foreach($account["details"] as $line) { 304 | $cd = array(); 305 | $cd["TRNTYPE"] = ENV_STR_OFX_TRNTYPE_DIRECTDEBIT; 306 | 307 | // 日付を取得する 308 | $cd["DTPOSTED"] = $line["date"]; 309 | 310 | // 通番を生成する 311 | if($cd["DTPOSTED"] == $cd_date) $cd_num++; else $cd_num = 0; 312 | 313 | // トランザクション番号を生成する 314 | $cd["FITID"] = $cd["DTPOSTED"] . "0000000" . sprintf("%05d", $cd_num); 315 | 316 | // 摘要を取得する 317 | $cd["NAME"] = $line["summary"]; 318 | 319 | // 金額を取得する 320 | $cd["TRNAMT"] = parse_amount($line["amount"]); 321 | $cd["MEMO"] = ENV_STR_OFX_MEMO; 322 | 323 | array_push($cds, $cd); 324 | $cd_date = $cd["DTPOSTED"]; 325 | } 326 | // BANKTRANLIST 327 | $ret .= ""; 328 | $ret .= "\r\n"; 329 | $ret .= "" . ENV_STR_DATE_PASTDAY . ENV_STR_OFX_TZ . ""; 330 | $ret .= "" . ENV_STR_DATE_TODAY . ENV_STR_OFX_TZ . ""; 331 | $ret .= "\r\n"; 332 | 333 | foreach($cds as $cd) { 334 | $ret .= ""; 335 | $ret .= "" . $cd["TRNTYPE"] . ""; 336 | $ret .= "" . $cd["DTPOSTED"] . ENV_STR_OFX_TZ . ""; 337 | $ret .= "" . $cd["TRNAMT"] . ""; 338 | $ret .= "" . $cd["FITID"] . ""; 339 | $ret .= "" . $cd["NAME"] . ""; 340 | $ret .= "" . $cd["MEMO"] . ""; 341 | $ret .= ""; 342 | $ret .= "\r\n"; 343 | } 344 | 345 | $ret .= ""; 346 | $ret .= "\r\n"; 347 | $ret .= ""; 348 | $ret .= "" . $account["balance"] . ""; 349 | $ret .= "" . ENV_STR_DATE_TODAY . ENV_STR_OFX_TZ . ""; 350 | $ret .= ""; 351 | $ret .= "\r\n"; 352 | 353 | // 口座名称を出力する 354 | if($account["acctname"] != "") { 355 | $ret .= "" . $account["acctname"] . ""; 356 | $ret .= "\r\n"; 357 | } 358 | 359 | return $ret; 360 | } 361 | 362 | ?> 363 | -------------------------------------------------------------------------------- /server/esaifu.inc: -------------------------------------------------------------------------------- 1 | 0) { 41 | $method = "GET"; 42 | $uris = parse_uri($locations[0], $uris); 43 | $query = ""; 44 | $cookie = esaifu_update_cookie($head, $cookie); 45 | list($head, $body) = esaifu_http11($method, $uris, $query, $cookie); 46 | } 47 | } 48 | 49 | // ログイン画面を取得する 50 | $as = parse_tag($body, "a"); 51 | foreach($as as $a) if(parse_tag_search(parse_tag($a["innerHTML"], "img"), "alt", "会員ログイン)") != -1) { 52 | $method = "GET"; 53 | $uris = parse_uri($a["href"], $uris); 54 | $query = ""; 55 | $cookie = esaifu_update_cookie($head, $cookie); 56 | list($head, $body) = esaifu_http11($method, $uris, $query, $cookie); 57 | break; 58 | } 59 | 60 | // 画像認証の画像を取得する 61 | $imgs = parse_tag($body, "img"); 62 | $c = parse_tag_search($imgs, "id", "siimage"); 63 | if($c != -1) { 64 | $imguris = parse_uri($imgs[$c]["src"], $uris); 65 | list($imghead, $imgbody) = esaifu_http11($method, $imguris, $query, $cookie, $uris["scheme"] . "://" . $uris["host"] . $uris["path"] . $query); 66 | $imgsrc = "data:image/png;base64," . base64_encode($imgbody); 67 | } 68 | 69 | // ログインする 70 | $forms = parse_tag($body, "form"); 71 | if(count($forms) > 0) { 72 | $inputs = parse_tag($forms[0]["innerHTML"], "input"); 73 | $queries = array(); 74 | foreach($inputs as $input) if($input["name"] != "") $queries[$input["name"]] = urlencode($input["name"]) . "=" . urlencode($input["value"]); 75 | $queries["user_id"] = "user_id=" . $user; 76 | $queries["password"] = "password=" . $pass; 77 | $queries["image_key"] = "image_key="; 78 | 79 | $method = $forms[0]["method"]; 80 | $uris = parse_uri($forms[0]["action"], $uris); 81 | $query = implode("&", $queries); 82 | $cookie = esaifu_update_cookie($head, $cookie); 83 | } 84 | 85 | // セッションを退避する 86 | $sid = 1; 87 | $head = ""; 88 | $body = ""; 89 | } else if($sid == 1) { 90 | // セッションを復元する 91 | $sid = 0; 92 | $uris = parse_uri($uri); 93 | $query = str_replace("image_key=", "image_key=" . $auth, $query); 94 | list($head, $body) = esaifu_http11($method, $uris, $query, $cookie); 95 | 96 | // リダイレクトする 97 | $forms = parse_tag($body, "form"); 98 | $c = parse_tag_search($forms, "id", "form1"); 99 | if($c != -1) { 100 | $scripts = parse_tag($body, "script"); 101 | foreach($scripts as $script) if(preg_match("/([\'\"])([^\\1]*?)\\1/i", $script["innerHTML"], $matches) > 0) { 102 | $forms[$c]["action"] = $matches[2]; 103 | 104 | $method = $forms[$c]["method"]; 105 | $uris = parse_uri($forms[$c]["action"], $uris); 106 | // $queryは一つ前のものを使い回す 107 | // $query = implode("&", $queries); 108 | $cookie = esaifu_update_cookie($head, $cookie); 109 | list($head, $body) = esaifu_http11($method, $uris, $query, $cookie); 110 | break; 111 | } 112 | } 113 | 114 | // リダイレクトする 115 | $retry = 0; 116 | while($retry++ < ENV_NUM_HTTP11_RETRY) { 117 | $locations = parse_header($head, "location"); 118 | if(count($locations) > 0) { 119 | $method = "GET"; 120 | $uris = parse_uri($locations[0], $uris); 121 | $query = ""; 122 | $cookie = esaifu_update_cookie($head, $cookie); 123 | list($head, $body) = esaifu_http11($method, $uris, $query, $cookie); 124 | } 125 | } 126 | } 127 | 128 | if($sid > 0) { 129 | // セッションを引き継ぐ 130 | $resp["status"] = ENV_NUM_STATUS_ADDITION; 131 | $resp["aid"] = "image_key"; 132 | $resp["additional"] = $imgsrc; 133 | $resp["sid"] = $sid; 134 | $resp["sesscookie"] = sess_encode(implode("\t", array($cookie, ENV_STR_SESSION_PADDING))); 135 | $resp["accesskey"] = sess_encode(implode("\t", array((string)$sid, $method, $uris["scheme"] . "://" . $uris["host"] . $uris["path"], $query, $user, ENV_STR_SESSION_PADDING))); 136 | 137 | $mfachallengetrnrs = ""; 138 | $mfachallengetrnrs .= ""; 139 | $mfachallengetrnrs .= ""; 140 | $mfachallengetrnrs .= ""; 141 | $mfachallengetrnrs .= "" . $resp["aid"] . ""; 142 | $mfachallengetrnrs .= "" . $resp["additional"] . ""; 143 | $mfachallengetrnrs .= ""; 144 | $mfachallengetrnrs .= ""; 145 | $mfachallengetrnrs .= ""; 146 | 147 | $resp["ofx"] = generate_ofx($resp["status"], $mfachallengetrnrs, $resp["sesscookie"], $resp["accesskey"]); 148 | } else if(strpos($body, "eさいふ | メンテナンス中") !== false) { 149 | // システムメンテナンス画面の場合 150 | $resp["status"] = ENV_NUM_STATUS_MAINTENANCE; 151 | $resp["method"] = $method; 152 | $resp["uri"] = $uris["scheme"] . "://" . $uris["host"] . $uris["path"]; 153 | $resp["query"] = $query; 154 | $resp["cookie"] = $cookie; 155 | $resp["head"] = $head; 156 | $resp["body"] = $body; 157 | $resp["ofx"] = generate_ofx($resp["status"]); 158 | } else if(strpos($body, "前回のご利用日時") === false) { 159 | // ログイン失敗の場合 160 | $resp["status"] = ENV_NUM_STATUS_FAILURE; 161 | $resp["method"] = $method; 162 | $resp["uri"] = $uris["scheme"] . "://" . $uris["host"] . $uris["path"]; 163 | $resp["query"] = $query; 164 | $resp["cookie"] = $cookie; 165 | $resp["head"] = $head; 166 | $resp["body"] = $body; 167 | $resp["ofx"] = generate_ofx($resp["status"]); 168 | } else { 169 | $account = array(); 170 | 171 | $account["acctname"] = $settings["name"]; 172 | 173 | // 支店番号を取得する 174 | $account["branchid"] = "0"; 175 | 176 | // 口座番号を取得する 177 | $account["acctid"] = $user; 178 | 179 | // 残高を取得する 180 | $ps = parse_tag($body, "p"); 181 | $c = parse_tag_search($ps, "class", "price"); 182 | if($c != -1) $account["balance"] = parse_amount(strip_tags($spans[0]["innerHTML"])); 183 | 184 | // 履歴画面を取得する 185 | $as = parse_tag($body, "a"); 186 | $c = parse_tag_search($as, "innerHTML", "履歴"); 187 | if($c != 1) { 188 | $method = "GET"; 189 | $uris = parse_uri($as[$c]["href"], $uris); 190 | $query = ""; 191 | $cookie = esaifu_update_cookie($head, $cookie); 192 | list($head, $body) = esaifu_http11($method, $uris, $query, $cookie); 193 | } 194 | 195 | // 履歴画面(1ページ目)を取得する 196 | $forms = parse_tag($body, "form"); 197 | if(count($forms) > 0) { 198 | $queries = array(); 199 | $inputs = parse_tag($forms[0]["innerHTML"], "input"); 200 | foreach($inputs as $input) if($input["name"] != "") $queries[$input["name"]] = urlencode($input["name"]) . "=" . urlencode($input["value"]); 201 | $selects = parse_tag($forms[0]["innerHTML"], "select"); 202 | foreach($selects as $select) { 203 | $options = parse_tag($select["innerHTML"], "option"); 204 | foreach($options as $option) if($select["name"] != "" && $option["selected"] == "selected") $queries[$select["name"]] = urlencode($select["name"]) . "=" . urlencode($option["value"]); 205 | } 206 | $queries["user_year_from"] = "user_year_from=" . (string)(integer)substr(ENV_STR_DATE_PASTDAY, 0, 4); 207 | $queries["user_month_from"] = "user_month_from=" . (string)(integer)substr(ENV_STR_DATE_PASTDAY, 4, 2); 208 | $queries["user_day_from"] = "user_day_from=" . (string)(integer)substr(ENV_STR_DATE_PASTDAY, 6, 2); 209 | $queries["user_year_to"] = "user_year_to=" . (string)(integer)substr(ENV_STR_DATE_TODAY, 0, 4); 210 | $queries["user_month_to"] = "user_month_to=" . (string)(integer)substr(ENV_STR_DATE_TODAY, 4, 2); 211 | $queries["user_day_to"] = "user_day_to=" . (string)(integer)substr(ENV_STR_DATE_TODAY, 6, 2); 212 | 213 | $method = $forms[0]["method"]; 214 | $uris = parse_uri($forms[0]["action"], $uris); 215 | $query = implode("&", $queries); 216 | $cookie = esaifu_update_cookie($head, $cookie); 217 | list($head, $body) = esaifu_http11($method, $uris, $query, $cookie); 218 | } 219 | 220 | $tbody = ""; 221 | 222 | // 無限ループする 223 | while(true) { 224 | // 明細を取得する 225 | $tables = parse_tag($body, "table"); 226 | $c = parse_tag_search($tables, "class", "only_pc"); 227 | if($c != -1) { 228 | $tbodys = parse_tag($tables[$c]["innerHTML"], "tbody"); 229 | if(count($tbodys) > 0) $tbody .= $tbodys[0]["innerHTML"]; 230 | } 231 | 232 | // 履歴画面(2ページ目以降)を取得する 233 | $as = parse_tag($body, "a"); 234 | $found = false; 235 | foreach($as as $a) { 236 | if(trim(strip_tags($a["innerHTML"])) == "次へ") { 237 | $method = "GET"; 238 | $uris = parse_uri($a["href"], $uris); 239 | $query = ""; 240 | $cookie = esaifu_update_cookie($head, $cookie); 241 | list($head, $body) = esaifu_http11($method, $uris, $query, $cookie); 242 | 243 | $found = true; 244 | break; 245 | } 246 | } 247 | 248 | // 見つからない場合、ループを抜ける 249 | if($found == false) break; 250 | } 251 | 252 | $account["details"] = esaifu_get_details($tbody); 253 | 254 | // 実行時間(タイムアウト)を再設定する 255 | @set_time_limit(ENV_NUM_TIMEOUT); 256 | 257 | // ログアウトする 258 | $as = parse_tag($body, "a"); 259 | foreach($as as $a) if(strip_tags($a["innerHTML"]) == "ログアウト") { 260 | $method = "GET"; 261 | $uris = parse_uri($a["href"], $uris); 262 | $query = ""; 263 | $cookie = esaifu_update_cookie($head, $cookie); 264 | list($head, $body) = esaifu_http11($method, $uris, $query, $cookie); 265 | break; 266 | } 267 | 268 | // リダイレクトする 269 | $retry = 0; 270 | while($retry++ < ENV_NUM_HTTP11_RETRY) { 271 | $locations = parse_header($head, "location"); 272 | if(count($locations) > 0) { 273 | $method = "GET"; 274 | $uris = parse_uri($locations[0], $uris); 275 | $query = ""; 276 | $cookie = esaifu_update_cookie($head, $cookie); 277 | list($head, $body) = esaifu_http11($method, $uris, $query, $cookie); 278 | } 279 | } 280 | 281 | // 実行時間(タイムアウト)を再設定する 282 | @set_time_limit(ENV_NUM_TIMEOUT); 283 | 284 | $bankmsgsrsv1 = ""; 285 | $bankmsgsrsv1 .= ""; 286 | $bankmsgsrsv1 .= "\r\n"; 287 | 288 | // 口座情報を取得する 289 | $bankmsgsrsv1 .= ""; 290 | $bankmsgsrsv1 .= "\r\n"; 291 | $bankmsgsrsv1 .= "0"; 292 | $bankmsgsrsv1 .= "\r\n"; 293 | $bankmsgsrsv1 .= "0INFO"; 294 | $bankmsgsrsv1 .= "\r\n"; 295 | $bankmsgsrsv1 .= ""; 296 | $bankmsgsrsv1 .= "\r\n"; 297 | $bankmsgsrsv1 .= "" . ENV_STR_OFX_CURRENCY_JPY . ""; 298 | $bankmsgsrsv1 .= "\r\n"; 299 | $bankmsgsrsv1 .= ""; 300 | $bankmsgsrsv1 .= "" . $settings["code"] . ""; 301 | $bankmsgsrsv1 .= "" . $account["branchid"] . ""; 302 | $bankmsgsrsv1 .= "" . $account["acctid"] . ""; 303 | $bankmsgsrsv1 .= "" . ENV_STR_ACCTTYPE_CHECKING . ""; 304 | $bankmsgsrsv1 .= ""; 305 | $bankmsgsrsv1 .= "\r\n"; 306 | $bankmsgsrsv1 .= esaifu_parse_details($account); 307 | $bankmsgsrsv1 .= ""; 308 | $bankmsgsrsv1 .= "\r\n"; 309 | $bankmsgsrsv1 .= ""; 310 | $bankmsgsrsv1 .= "\r\n"; 311 | 312 | $bankmsgsrsv1 .= ""; 313 | $bankmsgsrsv1 .= "\r\n"; 314 | 315 | // OFXファイルを出力する 316 | $resp["status"] = ENV_NUM_STATUS_SUCCESS; 317 | $resp["ofx"] = generate_ofx($resp["status"], $bankmsgsrsv1); 318 | } 319 | return $resp; 320 | 321 | // HTTP/1.1 322 | function esaifu_http11($method, $uris, $query = "", $cookie = "", $referer = "") { 323 | $ret = "INVALID HOST"; 324 | if(preg_match("/\.mun-prepaid\.com$/", $uris["host"]) > 0) $ret = http11(strtoupper($method), $uris["scheme"], $uris["host"], 0, $uris["path"], $query, "", $cookie, true, ENV_PRODUCT_UA, "", $referer); 325 | return explode("\r\n\r\n", $ret, 2); 326 | } 327 | 328 | function esaifu_update_cookie($head, $cookie) { 329 | return update_cookie(array("cookie_use_ok", "sslCookieUseOk", "vp_partner_id", "vp_session", "Nicos_pmk"), parse_header($head, "set-cookie"), $cookie); 330 | } 331 | 332 | function esaifu_get_details($body) { 333 | $rets = array(); 334 | $i = 0; 335 | $trs = parse_tag($body, "tr"); 336 | foreach($trs as $tr) { 337 | $tds = parse_tag($tr["innerHTML"], "td"); 338 | if(count($tds) == 7) { 339 | // 利用日付を取得する 340 | $dt = explode(" ", $tds[1]["innerHTML"]); 341 | $rets[$i]["date"] = parse_date(trim(strip_tags($dt[0]))); 342 | 343 | // ご利用種別、ご利用内容、およびお取引IDを取得する 344 | $buf = trim(strip_tags($tds[2]["innerHTML"])); 345 | switch($buf) { 346 | case "ご利用(予約)": 347 | $name = $buf; 348 | $memo = implode(ENV_CHR_CONCATENATOR, array(str_replace("カード下4桁 ", "", trim(strip_tags($tds[3]["innerHTML"]))), trim(strip_tags($tds[6]["innerHTML"])))); 349 | break; 350 | case "ご利用(確定)": 351 | list($name, $memo) = explode("
    ", $tds[3]["innerHTML"], 2); 352 | $name = trim(strip_tags($name)); 353 | $memo = implode(ENV_CHR_CONCATENATOR, array(str_replace("カード下4桁 ", "", trim(strip_tags($memo))), trim(strip_tags($tds[6]["innerHTML"])))); 354 | break; 355 | default: 356 | $name = trim(strip_tags($tds[3]["innerHTML"])); 357 | $memo = $buf; 358 | break; 359 | } 360 | $rets[$i]["summary"] = $name; 361 | $rets[$i]["memo"] = $memo; 362 | 363 | // ご利用金額を取得する 364 | $rets[$i]["amount"] = parse_amount(strip_tags($tds[4]["innerHTML"])); 365 | 366 | $i++; 367 | } 368 | } 369 | 370 | return $rets; 371 | } 372 | 373 | function esaifu_parse_details($account) { 374 | $ret = ""; 375 | $cds = array(); 376 | $cd_date = ""; 377 | $cd_num = 0; 378 | foreach($account["details"] as $line) { 379 | $cd = array(); 380 | $cd["TRNTYPE"] = ENV_STR_OFX_TRNTYPE_DIRECTDEBIT; 381 | 382 | // 日付を取得する 383 | $cd["DTPOSTED"] = $line["date"]; 384 | 385 | // 通番を生成する 386 | if($cd["DTPOSTED"] == $cd_date) $cd_num++; else $cd_num = 0; 387 | 388 | // トランザクション番号を生成する 389 | $cd["FITID"] = $cd["DTPOSTED"] . "0000000" . sprintf("%05d", $cd_num); 390 | 391 | // 摘要を取得する 392 | $cd["NAME"] = $line["summary"]; 393 | 394 | // 金額を取得する 395 | $cd["TRNAMT"] = parse_amount($line["amount"]); 396 | $cd["MEMO"] = ($line["memo"] != ""? $line["memo"]: ENV_STR_OFX_MEMO); 397 | 398 | array_push($cds, $cd); 399 | $cd_date = $cd["DTPOSTED"]; 400 | } 401 | // BANKTRANLIST 402 | $ret .= ""; 403 | $ret .= "\r\n"; 404 | $ret .= "" . ENV_STR_DATE_PASTDAY . ENV_STR_OFX_TZ . ""; 405 | $ret .= "" . ENV_STR_DATE_TODAY . ENV_STR_OFX_TZ . ""; 406 | $ret .= "\r\n"; 407 | 408 | foreach($cds as $cd) { 409 | $ret .= ""; 410 | $ret .= "" . $cd["TRNTYPE"] . ""; 411 | $ret .= "" . $cd["DTPOSTED"] . ENV_STR_OFX_TZ . ""; 412 | $ret .= "" . $cd["TRNAMT"] . ""; 413 | $ret .= "" . $cd["FITID"] . ""; 414 | $ret .= "" . $cd["NAME"] . ""; 415 | $ret .= "" . $cd["MEMO"] . ""; 416 | $ret .= ""; 417 | $ret .= "\r\n"; 418 | } 419 | 420 | $ret .= ""; 421 | $ret .= "\r\n"; 422 | $ret .= ""; 423 | $ret .= "" . $account["balance"] . ""; 424 | $ret .= "" . ENV_STR_DATE_TODAY . ENV_STR_OFX_TZ . ""; 425 | $ret .= ""; 426 | $ret .= "\r\n"; 427 | 428 | // 口座名称を出力する 429 | if($account["acctname"] != "") { 430 | $ret .= "" . $account["acctname"] . ""; 431 | $ret .= "\r\n"; 432 | } 433 | 434 | return $ret; 435 | } 436 | 437 | ?> 438 | -------------------------------------------------------------------------------- /server/jaccscard.inc: -------------------------------------------------------------------------------- 1 | 0) { 76 | $method = "GET"; 77 | $uris = parse_uri($locations[0], $uris); 78 | $query = ""; 79 | $cookie = jaccscard_update_cookie($head, $cookie); 80 | list($head, $body) = jaccscard_http11($method, $uris, $query, $cookie); 81 | } 82 | } 83 | 84 | if(strpos($body, "メンテナンスを行っております") !== false) { 85 | // システムメンテナンス画面の場合 86 | $resp["status"] = ENV_NUM_STATUS_MAINTENANCE; 87 | $resp["method"] = $method; 88 | $resp["uri"] = $uris["scheme"] . "://" . $uris["host"] . $uris["path"]; 89 | $resp["query"] = $query; 90 | $resp["cookie"] = $cookie; 91 | $resp["head"] = $head; 92 | $resp["body"] = $body; 93 | $resp["ofx"] = generate_ofx($resp["status"]); 94 | } else if(strpos($body, "前回ログイン") === false) { 95 | // ログイン失敗の場合 96 | $resp["status"] = ENV_NUM_STATUS_FAILURE; 97 | $resp["method"] = $method; 98 | $resp["uri"] = $uris["scheme"] . "://" . $uris["host"] . $uris["path"]; 99 | $resp["query"] = $query; 100 | $resp["cookie"] = $cookie; 101 | $resp["head"] = $head; 102 | $resp["body"] = $body; 103 | $resp["ofx"] = generate_ofx($resp["status"]); 104 | } else { 105 | $account = array(); 106 | 107 | // 実行時間(タイムアウト)を再設定する 108 | @set_time_limit(ENV_NUM_TIMEOUT); 109 | 110 | // ご利用状況の確認画面を取得する 111 | $forms = parse_tag($body, "form"); 112 | $c = parse_tag_search($forms, "name", "MainForm"); 113 | if($c != -1) { 114 | $inputs = parse_tag($forms[$c]["innerHTML"], "input"); 115 | $queries = array(); 116 | foreach($inputs as $input) if($input["name"] != "") $queries[$input["name"]] = urlencode($input["name"]) . "=" . urlencode($input["value"]); 117 | $queries["_TRANID"] = "_TRANID=JAMY00001_01M"; // ご利用状況の確認 118 | 119 | $method = $forms[$c]["method"]; 120 | $uris = parse_uri($forms[$c]["action"], $uris); 121 | $query = implode("&", $queries); 122 | $cookie = jaccscard_update_cookie($head, $cookie); 123 | list($head, $body) = jaccscard_http11($method, $uris, $query, $cookie); 124 | } 125 | 126 | // ご利用代金明細を見る画面を取得する 127 | $forms = parse_tag($body, "form"); 128 | $c = parse_tag_search($forms, "name", "MainForm"); 129 | if($c != -1) { 130 | $inputs = parse_tag($forms[$c]["innerHTML"], "input"); 131 | $queries = array(); 132 | foreach($inputs as $input) if($input["name"] != "") $queries[$input["name"]] = urlencode($input["name"]) . "=" . urlencode($input["value"]); 133 | $queries["_TRANID"] = "_TRANID=JAST00001_21M"; // ご利用代金明細を見る 134 | $queries["_SUBINDEX"] = "_SUBINDEX=0"; // (カードが複数枚存在する場合)最初のカード 135 | 136 | $method = $forms[$c]["method"]; 137 | $uris = parse_uri($forms[$c]["action"], $uris); 138 | $query = implode("&", $queries); 139 | $cookie = jaccscard_update_cookie($head, $cookie); 140 | list($head, $body) = jaccscard_http11($method, $uris, $query, $cookie); 141 | } 142 | 143 | // お支払日を取得する 144 | $trs = parse_tag($body, "tr", true); // 再帰的に取得する 145 | $c = parse_tag_search($trs, "class", "first"); 146 | if($c != -1) { 147 | $tds = parse_tag($trs[$c]["innerHTML"], "td"); 148 | if(count($tds) >= 1) $account["paydate"] = parse_date(trim(str_replace("\t", "", $tds[0]["innerHTML"]))); 149 | } 150 | 151 | // カード名・カード番号を取得する 152 | $dds = parse_tag($body, "dd"); 153 | if(count($dds) >= 2) { 154 | $account["acctname"] = implode(ENV_CHR_CONCATENATOR, array($settings["name"], $dds[0]["innerHTML"])); 155 | $account["name"] = $settings["name"]; 156 | $account["acctid"] = strip_tags(str_replace("∗", "*", $dds[1]["innerHTML"])); 157 | } 158 | 159 | $body_old = $body; 160 | 161 | // CSVファイルをダウンロードする 162 | $forms = parse_tag($body, "form"); 163 | $c = parse_tag_search($forms, "name", "MainForm"); 164 | if($c != -1) { 165 | $inputs = parse_tag($forms[$c]["innerHTML"], "input"); 166 | $queries = array(); 167 | foreach($inputs as $input) if($input["name"] != "") $queries[$input["name"]] = urlencode($input["name"]) . "=" . urlencode($input["value"]); 168 | $queries["_TRANID"] = "_TRANID=JAST00016_23C"; // 明細をCSVで保存する 169 | 170 | $method = $forms[$c]["method"]; 171 | $uris = parse_uri($forms[$c]["action"], $uris); 172 | $query = implode("&", $queries); 173 | $cookie = jaccscard_update_cookie($head, $cookie); 174 | list($head, $body) = jaccscard_http11($method, $uris, $query, $cookie); 175 | 176 | if(strpos($head, "Content-Type: text/html") === false) { 177 | $creditcardmsgsrsv1 = ""; 178 | $creditcardmsgsrsv1 .= ""; 179 | $creditcardmsgsrsv1 .= "\r\n"; 180 | 181 | $creditcardmsgsrsv1 .= ""; 182 | $creditcardmsgsrsv1 .= "\r\n"; 183 | $creditcardmsgsrsv1 .= "0"; 184 | $creditcardmsgsrsv1 .= "\r\n"; 185 | $creditcardmsgsrsv1 .= "0INFO"; 186 | $creditcardmsgsrsv1 .= "\r\n"; 187 | $creditcardmsgsrsv1 .= ""; 188 | $creditcardmsgsrsv1 .= "\r\n"; 189 | $creditcardmsgsrsv1 .= "" . ENV_STR_OFX_CURRENCY_JPY . ""; 190 | $creditcardmsgsrsv1 .= "\r\n"; 191 | $creditcardmsgsrsv1 .= ""; 192 | $creditcardmsgsrsv1 .= "" . $account["acctid"] . ""; 193 | $creditcardmsgsrsv1 .= ""; 194 | $creditcardmsgsrsv1 .= "\r\n"; 195 | $creditcardmsgsrsv1 .= jaccscard_parse_csv($body, $account); 196 | $creditcardmsgsrsv1 .= ""; 197 | $creditcardmsgsrsv1 .= "\r\n"; 198 | $creditcardmsgsrsv1 .= ""; 199 | $creditcardmsgsrsv1 .= "\r\n"; 200 | 201 | $creditcardmsgsrsv1 .= ""; 202 | $creditcardmsgsrsv1 .= "\r\n"; 203 | } 204 | 205 | } 206 | 207 | $body = $body_old; 208 | 209 | // 実行時間(タイムアウト)を再設定する 210 | @set_time_limit(ENV_NUM_TIMEOUT); 211 | 212 | // ログアウトする 213 | $forms = parse_tag($body, "form"); 214 | $c = parse_tag_search($forms, "name", "MainForm"); 215 | if($c != -1) { 216 | $inputs = parse_tag($forms[$c]["innerHTML"], "input"); 217 | $queries = array(); 218 | foreach($inputs as $input) if($input["name"] != "") $queries[$input["name"]] = urlencode($input["name"]) . "=" . urlencode($input["value"]); 219 | $queries["_TRANID"] = "_TRANID=JALG00012_00M"; // ログアウト 220 | 221 | $method = $forms[$c]["method"]; 222 | $uris = parse_uri($forms[$c]["action"], $uris); 223 | $query = implode("&", $queries); 224 | $cookie = jaccscard_update_cookie($head, $cookie); 225 | list($head, $body) = jaccscard_http11($method, $uris, $query, $cookie); 226 | } 227 | 228 | // OFXファイルを出力する 229 | $resp["status"] = ENV_NUM_STATUS_SUCCESS; 230 | if(strpos($creditcardmsgsrsv1, "") === false) { 231 | // 明細が存在しない場合 232 | $resp["ofx"] = generate_ofx($resp["status"]); 233 | } else { 234 | // 明細が存在する場合 235 | $resp["ofx"] = generate_ofx($resp["status"], $creditcardmsgsrsv1); 236 | } 237 | } 238 | return $resp; 239 | 240 | // HTTP/1.1 241 | function jaccscard_http11($method, $uris, $query = "", $cookie = "") { 242 | $ret = "INVALID HOST"; 243 | if(preg_match("/\.jaccs\.co\.jp$/", $uris["host"]) > 0) $ret = http11(strtoupper($method), $uris["scheme"], $uris["host"], 0, $uris["path"], $query, "", $cookie); 244 | return explode("\r\n\r\n", $ret, 2); 245 | } 246 | 247 | function jaccscard_update_cookie($head, $cookie) { 248 | return update_cookie(array("JSESSIONID", "[0-9]{17}"), parse_header($head, "set-cookie"), $cookie); 249 | } 250 | 251 | function jaccscard_parse_csv($str, $account) { 252 | $ret = ""; 253 | $lines = parse_csv(mb_convert_string($str)); 254 | $cds = array(); 255 | $cds_balamt = "0"; 256 | $cds_paydate = $account["paydate"]; 257 | $cds_s = ""; 258 | $cds_e = ""; 259 | $cd_date = ""; 260 | $cd_num = 0; 261 | $ledge_balamt = 0; 262 | $flg = false; 263 | 264 | foreach($lines as $line) { 265 | $cd = array(); 266 | 267 | if(count($line) == 2 && $line[0] == "(A)1回・2回・分割・ボーナス払の今回お支払金額小計") { 268 | // 今回お支払金額を取得する 269 | $cds_balamt = (string)((double)parse_amount($line[1])); 270 | } else if(count($line) == 13 && $line[1] == "<<次回以降のお支払明細>>") { 271 | // 次回以降のお支払明細を処理しない 272 | $flg = true; 273 | // break; 274 | } else if(count($line) == 13 && $line[0] != "ご利用年月日" && $line[0] != "" && $flg == false) { 275 | // PAYMENT固定とする 276 | $cd["TRNTYPE"] = ENV_STR_OFX_TRNTYPE_PAYMENT; 277 | 278 | // 日付を取得する 279 | $cd["DTPOSTED"] = parse_date($line[0]); 280 | if($cds_s == "") $cds_s = $cd["DTPOSTED"]; 281 | $cds_e = $cd["DTPOSTED"]; 282 | 283 | // 通番を生成する 284 | if($cd["DTPOSTED"] == $cd_date) $cd_num++; else $cd_num = 0; 285 | 286 | // トランザクション番号を生成する 287 | $cd["FITID"] = $cd["DTPOSTED"] . sprintf("%04d", $account["id"]) . substr($account["paydate"], 4, 2) . "0" . sprintf("%05d", $cd_num); 288 | 289 | // 摘要を取得する 290 | $cd["NAME"] = $line[1]; 291 | 292 | // 金額を取得する 293 | $cd["TRNAMT"] = (string)(-1 * (double)parse_amount($line[7])); 294 | 295 | // 費目を取得する 296 | $cd["MEMO"] = ($line[12] != "未設定"? $line[12]: ENV_STR_OFX_MEMO); 297 | 298 | // 残高を取得する 299 | $ledge_balamt += (double)$cd["TRNAMT"]; 300 | 301 | array_push($cds, $cd); 302 | $cd_date = $cd["DTPOSTED"]; 303 | } 304 | } 305 | 306 | $ledge_balamt += (double)$cds_balamt; 307 | 308 | if($cds_s == "") $cds_s = ENV_STR_DATE_TODAY; 309 | if($cds_e == "") $cds_e = ENV_STR_DATE_TODAY; 310 | if($cds_s > $cds_e) $cds_e = $cds_s; 311 | 312 | // クレジットカード支払請求を明細に追加する 313 | $i = count($cds); 314 | $cds[$i]["DTPOSTED"] = $cds_paydate; 315 | $cds[$i]["NAME"] = $account["name"]; 316 | $cds[$i]["MEMO"] = ENV_STR_OFX_MEMO; 317 | $cds[$i]["TRNAMT"] = $cds_balamt; 318 | $cds[$i]["TRNTYPE"] = ENV_STR_OFX_TRNTYPE_DIRECTDEBIT; 319 | $cds[$i]["FITID"] = $cds[$i]["DTPOSTED"] . sprintf("%04d", $account["id"]) . substr($account["paydate"], 4, 2) . "100000"; 320 | 321 | // BANKTRANLIST 322 | $ret .= ""; 323 | $ret .= "\r\n"; 324 | $ret .= "" . $cds_s . ENV_STR_OFX_TZ . ""; 325 | $ret .= "" . $cds_e . ENV_STR_OFX_TZ . ""; 326 | $ret .= "\r\n"; 327 | 328 | foreach($cds as $cd) { 329 | $ret .= ""; 330 | $ret .= "" . $cd["TRNTYPE"] . ""; 331 | $ret .= "" . $cd["DTPOSTED"] . ENV_STR_OFX_TZ . ""; 332 | $ret .= "" . $cd["TRNAMT"] . ""; 333 | $ret .= "" . $cd["FITID"] . ""; 334 | $ret .= "" . $cd["NAME"] . ""; 335 | $ret .= "" . $cd["MEMO"] . ""; 336 | $ret .= ""; 337 | $ret .= "\r\n"; 338 | } 339 | 340 | $ret .= ""; 341 | $ret .= "\r\n"; 342 | 343 | // 支払後残高を出力する 344 | $ret .= ""; 345 | $ret .= "" . (string)$ledge_balamt . ""; 346 | $ret .= "" . ENV_STR_DATE_TODAY . ENV_STR_OFX_TZ . ""; 347 | $ret .= ""; 348 | $ret .= "\r\n"; 349 | 350 | // カード名称を出力する 351 | if($account["acctname"] != "") { 352 | $ret .= "" . $account["acctname"] . ""; 353 | $ret .= "\r\n"; 354 | } 355 | 356 | return $ret; 357 | } 358 | 359 | ?> 360 | -------------------------------------------------------------------------------- /server/mobilesuica.inc: -------------------------------------------------------------------------------- 1 | 0) { 76 | // セッションを引き継ぐ 77 | $resp["status"] = ENV_NUM_STATUS_ADDITION; 78 | $resp["aid"] = "WebCaptcha1__editor"; 79 | $resp["additional"] = $imgsrc; 80 | $resp["sid"] = $sid; 81 | $resp["sesscookie"] = sess_encode(implode("\t", array($cookie, ENV_STR_SESSION_PADDING))); 82 | $resp["accesskey"] = sess_encode(implode("\t", array((string)$sid, $method, $uris["scheme"] . "://" . $uris["host"] . $uris["path"], $query, $user, ENV_STR_SESSION_PADDING))); 83 | 84 | $mfachallengetrnrs = ""; 85 | $mfachallengetrnrs .= ""; 86 | $mfachallengetrnrs .= ""; 87 | $mfachallengetrnrs .= ""; 88 | $mfachallengetrnrs .= "" . $resp["aid"] . ""; 89 | $mfachallengetrnrs .= "" . $resp["additional"] . ""; 90 | $mfachallengetrnrs .= ""; 91 | $mfachallengetrnrs .= ""; 92 | $mfachallengetrnrs .= ""; 93 | 94 | $resp["ofx"] = generate_ofx($resp["status"], $mfachallengetrnrs, $resp["sesscookie"], $resp["accesskey"]); 95 | } else if(strpos($body, "SF(電子マネー)利用履歴") === false) { 96 | // ログイン失敗の場合 97 | $resp["status"] = ENV_NUM_STATUS_FAILURE; 98 | $resp["method"] = $method; 99 | $resp["uri"] = $uris["scheme"] . "://" . $uris["host"] . $uris["path"]; 100 | $resp["query"] = $query; 101 | $resp["cookie"] = $cookie; 102 | $resp["head"] = $head; 103 | $resp["body"] = $body; 104 | $resp["ofx"] = generate_ofx($resp["status"]); 105 | } else { 106 | $account = array(); 107 | 108 | $account["acctname"] = $settings["name"] . ENV_CHR_CONCATENATOR . $user; 109 | 110 | // 支店番号を取得する 111 | $account["branchid"] = "0"; 112 | 113 | // 口座番号を取得する 114 | $account["acctid"] = $user; 115 | 116 | // 残高を取得する 117 | $account["balance"] = 0; 118 | 119 | // SF(電子マネー)利用履歴画面を取得する 120 | $as = parse_tag($body, "a"); 121 | foreach($as as $a) if(parse_tag_search(parse_tag($a["innerHTML"], "img"), "alt", "SF(電子マネー)利用履歴") != -1) { 122 | $method = "POST"; 123 | if(preg_match("/javascript:[^\']+?\'([^\']+)\'.*?/i", $a["href"], $matches) > 0) $uris = parse_uri($matches[1], $uris); 124 | $query = ""; 125 | $cookie = mobilesuica_update_cookie($head, $cookie); 126 | list($head, $body) = mobilesuica_http11($method, $uris, $query, $cookie); 127 | break; 128 | } 129 | 130 | $account["details"] = array(); 131 | $tables = parse_tag($body, "table", true); // 再帰的に取得する 132 | foreach($tables as $table) if($table["cellpadding"] == "8") { 133 | $account["details"] = mobilesuica_get_details($table["innerHTML"]); 134 | $detail = array_shift($account["details"]); 135 | $account["balance"] = $detail["amount"]; 136 | } 137 | 138 | // SuicaID番号を取得する 139 | $forms = parse_tag($body, "form", true); // 再帰的に取得する 140 | $c = parse_tag_search($forms, "name", "form1"); 141 | if($c != -1) { 142 | $inputs = parse_tag($forms[$c]["innerHTML"], "input"); 143 | $queries = array(); 144 | foreach($inputs as $input) if($input["name"] != "") $queries[$input["name"]] = urlencode($input["name"]) . "=" . urlencode($input["value"]); 145 | $selects = parse_tag($forms[$c]["innerHTML"], "select"); 146 | foreach($selects as $select) { 147 | $options = parse_tag($select["innerHTML"], "option"); 148 | foreach($options as $option) if($select["name"] != "" && $option["selected"] == "selected") $queries[$select["name"]] = urlencode($select["name"]) . "=" . urlencode($option["value"]); 149 | } 150 | $queries["baseVarCopy"] = "baseVarCopy=" . substr($queries["baseVariable"], strpos($queries["baseVariable"], "=") + 1); 151 | if($queries["SEARCH"] != "") unset($queries["SEARCH"]); 152 | if($queries["RETURNMENU"] != "") unset($queries["RETURNMENU"]); 153 | 154 | $method = $forms[$c]["method"]; 155 | $uris = parse_uri($forms[$c]["action"], $uris); 156 | $query = implode("&", $queries); 157 | $cookie = mobilesuica_update_cookie($head, $cookie); 158 | list($head, $body) = mobilesuica_http11($method, $uris, $query, $cookie); 159 | 160 | $contentdispositions = parse_header($head, "content-disposition"); 161 | if(count($contentdispositions) > 0) { 162 | $account["acctid"] = substr($contentdispositions[0], strpos($contentdispositions[0], "=") + 1, 17); 163 | } 164 | 165 | } 166 | 167 | // 実行時間(タイムアウト)を再設定する 168 | @set_time_limit(ENV_NUM_TIMEOUT); 169 | 170 | // ログアウトする 171 | $method = "POST"; 172 | $uris = parse_uri("/ka/lg/LogoutComplete.aspx", $uris); 173 | $query = ""; 174 | $cookie = mobilesuica_update_cookie($head, $cookie); 175 | list($head, $body) = mobilesuica_http11($method, $uris, $query, $cookie); 176 | 177 | // 実行時間(タイムアウト)を再設定する 178 | @set_time_limit(ENV_NUM_TIMEOUT); 179 | 180 | $bankmsgsrsv1 = ""; 181 | $bankmsgsrsv1 .= ""; 182 | $bankmsgsrsv1 .= "\r\n"; 183 | 184 | // 口座情報を取得する 185 | $bankmsgsrsv1 .= ""; 186 | $bankmsgsrsv1 .= "\r\n"; 187 | $bankmsgsrsv1 .= "0"; 188 | $bankmsgsrsv1 .= "\r\n"; 189 | $bankmsgsrsv1 .= "0INFO"; 190 | $bankmsgsrsv1 .= "\r\n"; 191 | $bankmsgsrsv1 .= ""; 192 | $bankmsgsrsv1 .= "\r\n"; 193 | $bankmsgsrsv1 .= "" . ENV_STR_OFX_CURRENCY_JPY . ""; 194 | $bankmsgsrsv1 .= "\r\n"; 195 | $bankmsgsrsv1 .= ""; 196 | $bankmsgsrsv1 .= "" . $settings["code"] . ""; 197 | $bankmsgsrsv1 .= "" . $account["branchid"] . ""; 198 | $bankmsgsrsv1 .= "" . $account["acctid"] . ""; 199 | $bankmsgsrsv1 .= "" . ENV_STR_ACCTTYPE_CHECKING . ""; 200 | $bankmsgsrsv1 .= ""; 201 | $bankmsgsrsv1 .= "\r\n"; 202 | $bankmsgsrsv1 .= mobilesuica_parse_details($account); 203 | $bankmsgsrsv1 .= ""; 204 | $bankmsgsrsv1 .= "\r\n"; 205 | $bankmsgsrsv1 .= ""; 206 | $bankmsgsrsv1 .= "\r\n"; 207 | 208 | $bankmsgsrsv1 .= ""; 209 | $bankmsgsrsv1 .= "\r\n"; 210 | 211 | // OFXファイルを出力する 212 | $resp["status"] = ENV_NUM_STATUS_SUCCESS; 213 | $resp["ofx"] = generate_ofx($resp["status"], $bankmsgsrsv1); 214 | } 215 | return $resp; 216 | 217 | // HTTP/1.1 218 | function mobilesuica_http11($method, $uris, $query = "", $cookie = "", $referer = "", $autoconv = true) { 219 | $ret = "INVALID HOST"; 220 | if(preg_match("/\.mobilesuica\.com$/", $uris["host"]) > 0) $ret = http11(strtoupper($method), $uris["scheme"], $uris["host"], 0, $uris["path"], $query, "", $cookie, $autoconv, ENV_PRODUCT_UA . " MSIE 7.0", "", $referer); // ログイン時にUser-Agentをチェックされる 221 | return explode("\r\n\r\n", $ret, 2); 222 | } 223 | 224 | function mobilesuica_update_cookie($head, $cookie) { 225 | return update_cookie(array("ASP.NET_SessionId", "sc_auth"), parse_header($head, "set-cookie"), $cookie); 226 | } 227 | 228 | function mobilesuica_get_details($body) { 229 | $rets = array(); 230 | $trs = parse_tag($body, "tr"); 231 | array_shift($trs); 232 | $i = count($trs) - 1; 233 | $prev = ""; 234 | $last = ""; 235 | foreach($trs as $tr) { 236 | $tds = parse_tag($tr["innerHTML"], "td"); 237 | if(count($tds) == 7) { 238 | // 日時を取得する 239 | $dt = trim(str_replace("/", "", strip_tags($tds[0]["innerHTML"]))); 240 | if($dt > substr(ENV_STR_DATE_TODAY, 4, 4)) { 241 | $dt = (string)((integer)substr(ENV_STR_DATE_TODAY, 0, 4) - 1) . $dt; 242 | } else { 243 | $dt = substr(ENV_STR_DATE_TODAY, 0, 4) . $dt; 244 | } 245 | 246 | // 取引種別、および場所を取得する 247 | $class1 = mobilesuica_parse_string($tds[1]["innerHTML"]); 248 | $place1 = mobilesuica_parse_string($tds[2]["innerHTML"]); 249 | $class2 = mobilesuica_parse_string($tds[3]["innerHTML"]); 250 | $place2 = mobilesuica_parse_string($tds[4]["innerHTML"]); 251 | 252 | $name = $class1 . $class2; 253 | $memo = $place1; 254 | if($place2 != "") $memo .= "-" . $place2; 255 | if($memo == "") $memo = ENV_STR_OFX_MEMO; 256 | 257 | // 収支を計算する 258 | $amount = mobilesuica_parse_string($tds[6]["innerHTML"]); 259 | 260 | // 残高を取得する 261 | if($last == "") $last = parse_amount(str_replace("¥", "", trim(strip_tags($tds[5]["innerHTML"])))); 262 | 263 | $rets[$i]["date"] = $dt; 264 | $rets[$i]["summary"] = $name; 265 | $rets[$i]["amount"] = $amount; 266 | $rets[$i]["memo"] = $memo; 267 | 268 | $i--; 269 | } 270 | } 271 | $rets[0]["amount"] = $last; 272 | 273 | // 戻り値の配列の先頭が残高となる(明細としては無効) 274 | return array_reverse($rets); 275 | } 276 | 277 | function mobilesuica_parse_string($str) { 278 | return trim(mb_convert_kana(strip_tags($str), "sKV", "UTF-8")); 279 | } 280 | 281 | function mobilesuica_parse_details($account) { 282 | $ret = ""; 283 | $cds = array(); 284 | $cd_date = ""; 285 | $cd_num = 0; 286 | $dtstart = ENV_STR_DATE_PASTDAY; 287 | foreach($account["details"] as $line) { 288 | if($dtstart > $line["date"]) $dtstart = $line["date"]; 289 | 290 | $cd = array(); 291 | $cd["TRNTYPE"] = ENV_STR_OFX_TRNTYPE_DIRECTDEBIT; 292 | 293 | // 日付を取得する 294 | $cd["DTPOSTED"] = $line["date"]; 295 | 296 | // 通番を生成する 297 | if($cd["DTPOSTED"] == $cd_date) $cd_num++; else $cd_num = 0; 298 | 299 | // トランザクション番号を生成する 300 | $cd["FITID"] = $cd["DTPOSTED"] . "0000000" . sprintf("%05d", $cd_num); 301 | 302 | // 摘要を取得する 303 | $cd["NAME"] = $line["summary"]; 304 | 305 | // 金額を取得する 306 | $cd["TRNAMT"] = parse_amount($line["amount"]); 307 | $cd["MEMO"] = ($line["memo"] != ""? $line["memo"]: ENV_STR_OFX_MEMO); 308 | 309 | array_push($cds, $cd); 310 | $cd_date = $cd["DTPOSTED"]; 311 | } 312 | // BANKTRANLIST 313 | $ret .= ""; 314 | $ret .= "\r\n"; 315 | $ret .= "" . $dtstart . ENV_STR_OFX_TZ . ""; 316 | $ret .= "" . ENV_STR_DATE_TODAY . ENV_STR_OFX_TZ . ""; 317 | $ret .= "\r\n"; 318 | 319 | foreach($cds as $cd) { 320 | $ret .= ""; 321 | $ret .= "" . $cd["TRNTYPE"] . ""; 322 | $ret .= "" . $cd["DTPOSTED"] . ENV_STR_OFX_TZ . ""; 323 | $ret .= "" . $cd["TRNAMT"] . ""; 324 | $ret .= "" . $cd["FITID"] . ""; 325 | $ret .= "" . $cd["NAME"] . ""; 326 | $ret .= "" . $cd["MEMO"] . ""; 327 | $ret .= ""; 328 | $ret .= "\r\n"; 329 | } 330 | 331 | $ret .= ""; 332 | $ret .= "\r\n"; 333 | $ret .= ""; 334 | $ret .= "" . $account["balance"] . ""; 335 | $ret .= "" . ENV_STR_DATE_TODAY . ENV_STR_OFX_TZ . ""; 336 | $ret .= ""; 337 | $ret .= "\r\n"; 338 | 339 | // 口座名称を出力する 340 | if($account["acctname"] != "") { 341 | $ret .= "" . $account["acctname"] . ""; 342 | $ret .= "\r\n"; 343 | } 344 | 345 | return $ret; 346 | } 347 | 348 | ?> 349 | -------------------------------------------------------------------------------- /server/mufgcard.inc: -------------------------------------------------------------------------------- 1 | 0) { 74 | $method = "GET"; 75 | $uris = parse_uri($locations[0], $uris); 76 | $query = ""; 77 | $cookie = mun_update_cookie($head, $cookie); 78 | list($head, $body) = mun_http11($method, $uris, $query, $cookie); 79 | } 80 | } 81 | 82 | $as = parse_tag($body, "a"); 83 | foreach($as as $a) { 84 | switch(trim(strip_tags($a["innerHTML"]))) { 85 | case "ログアウト": 86 | // ログアウト画面を退避する(NEWS+PLUS) 87 | $method_mun = "GET"; 88 | $uris_mun = parse_uri($a["href"], $uris); 89 | $query_mun = ""; 90 | $cookie_mun = $cookie; 91 | break; 92 | case "WEBサービストップ": 93 | // WEBサービストップ画面を取得する(NEWS+PLUS) 94 | $method = "GET"; 95 | $uris = parse_uri($a["href"], $uris); 96 | $query = ""; 97 | $cookie = mun_update_cookie($head, $cookie); 98 | list($head, $body) = mun_http11($method, $uris, $query, $cookie); 99 | break; 100 | default: 101 | break; 102 | } 103 | } 104 | 105 | // 以降は各カードブランドの画面に遷移する 106 | $cookie = ""; 107 | 108 | // 実行時間(タイムアウト)を再設定する 109 | @set_time_limit(ENV_NUM_TIMEOUT); 110 | 111 | // ログインする 112 | $forms = parse_tag($body, "form"); 113 | $c = parse_tag_search($forms, "id", "seamlessForm"); 114 | if($c != -1) { 115 | $inputs = parse_tag($forms[$c]["innerHTML"], "input"); 116 | $queries = array(); 117 | foreach($inputs as $input) if($input["name"] != "") $queries[$input["name"]] = urlencode($input["name"]) . "=" . urlencode($input["value"]); 118 | 119 | $method = $forms[$c]["method"]; 120 | $uris = parse_uri($forms[$c]["action"], $uris); 121 | $query = implode("&", $queries); 122 | $cookie = mufgcard_updatecookie($head, $cookie); 123 | list($head, $body) = mufgcard_http11($method, $uris["scheme"], $uris["host"], $uris["path"], $query, $cookie); 124 | } 125 | 126 | // リダイレクトする 127 | $retry = 0; 128 | while($retry++ < ENV_NUM_HTTP11_RETRY) { 129 | $locations = parse_header($head, "location"); 130 | if(count($locations) > 0) { 131 | $method = "GET"; 132 | $uris = parse_uri($locations[0], $uris); 133 | $query = ""; 134 | $cookie = mufgcard_updatecookie($head, $cookie); 135 | list($head, $body) = mufgcard_http11($method, $uris["scheme"], $uris["host"], $uris["path"], $query, $cookie); 136 | } 137 | } 138 | 139 | if(strpos($body, "現在サービス停止中") !== false || strpos($body, "システムメンテナンスのため") !== false) { 140 | // システムメンテナンス画面の場合 141 | $resp["status"] = ENV_NUM_STATUS_MAINTENANCE; 142 | $resp["method"] = $method; 143 | $resp["uri"] = $uris["scheme"] . "://" . $uris["host"] . $uris["path"]; 144 | $resp["query"] = $query; 145 | $resp["cookie"] = $cookie; 146 | $resp["head"] = $head; 147 | $resp["body"] = $body; 148 | $resp["ofx"] = generate_ofx($resp["status"]); 149 | } else if(strpos($body, "前回ログイン") === false) { 150 | // ログイン失敗の場合 151 | $resp["status"] = ENV_NUM_STATUS_FAILURE; 152 | $resp["method"] = $method; 153 | $resp["uri"] = $uris["scheme"] . "://" . $uris["host"] . $uris["path"]; 154 | $resp["query"] = $query; 155 | $resp["cookie"] = $cookie; 156 | $resp["head"] = $head; 157 | $resp["body"] = $body; 158 | $resp["ofx"] = generate_ofx($resp["status"]); 159 | } else { 160 | // ログアウト画面を退避する 161 | $uris_old = parse_uri("/inet/dy/logout.html", $uris); 162 | 163 | // 請求額・利用明細照会 164 | $method = "GET"; 165 | $uris = parse_uri("/inet/dy/meisaisyokai/index.html", $uris); 166 | $query = ""; 167 | $cookie = mufgcard_updatecookie($head, $cookie); 168 | list($head, $body) = mufgcard_http11($method, $uris["scheme"], $uris["host"], $uris["path"], $query, $cookie); 169 | 170 | $tables = parse_tag($body, "table"); 171 | $tds = parse_tag($tables[0]["innerHTML"], "td"); 172 | // カード名称を取得する 173 | $account["acctname"] = implode(ENV_CHR_CONCATENATOR, array($settings["name"], $tds[1]["innerHTML"])); 174 | 175 | // カード番号を取得する 176 | if(preg_match("/XXXX-([0-9X]{4})/", $tds[2]["innerHTML"], $matches) > 0) { 177 | $account["acctid"] = $matches[1]; 178 | } 179 | 180 | // お支払日を取得する 181 | $tds = parse_tag($tables[1]["innerHTML"], "td"); 182 | $account["paydate"] = parse_date($tds[1]["innerHTML"]); 183 | 184 | // 今回ご請求合計額を取得する 185 | $account["ledge_balamt"] = 0; 186 | for( $i = 0 ; $i < 3 ; $i++ ) { 187 | $tmp = parse_amount($tds[2+$i*4]["innerHTML"]); 188 | $account["ledge_balamt"] += (-1)*$tmp; 189 | } 190 | 191 | // 実行時間(タイムアウト)を再設定する 192 | @set_time_limit(ENV_NUM_TIMEOUT); 193 | 194 | $bodies = array(); 195 | // カード・照会月を選択する 196 | $as = parse_tag($body, "a"); 197 | foreach($as as $a){ 198 | if(preg_match("/.*detail.*/", $a["href"])) { 199 | $method = "GET"; 200 | $uris = parse_uri($a["href"], $uris); 201 | $cookie = mufgcard_updatecookie($head, $cookie); 202 | list($head, $body) = mufgcard_http11($method, $uris["scheme"], $uris["host"], $uris["path"], $uris["query"], $cookie); 203 | array_push($bodies, $body); 204 | while(preg_match("/.*next\.html.*/", $body)) { 205 | $forms = parse_tag($body, "form"); 206 | $c = parse_tag_search($forms, "action", "/inet/dy/meisaisyokai/next.html#meisai"); 207 | $inputs = parse_tag($forms[$c]["innerHTML"], "input"); 208 | $queries = array(); 209 | foreach($inputs as $input) if($input["name"] != "") $queries[$input["name"]] = urlencode($input["name"]) . "=" . urlencode($input["value"]); 210 | 211 | $method = $forms[$c]["method"]; 212 | $uris = parse_uri($forms[$c]["action"], $uris); 213 | $query = implode("&", $queries); 214 | $cookie = mufgcard_updatecookie($head, $cookie); 215 | list($head, $body) = mufgcard_http11($method, $uris["scheme"], $uris["host"], $uris["path"], $query, $cookie); 216 | array_push($bodies, $body); 217 | } 218 | } 219 | } 220 | 221 | // DOMツリーを生成 222 | $ofxdom = new ofxDOM("CREDITCARD", $account["acctname"]); 223 | $ofxdom->setAcctfrom(array("ACCTID" => $account["acctid"])); 224 | 225 | // 明細をパース 226 | $cds = array(); 227 | foreach($bodies as $body){ 228 | $cds_tmp = mufgcard_parsedom($body); 229 | if ($cds_tmp != false) { 230 | $cds = array_merge($cds, $cds_tmp); 231 | } 232 | } 233 | usort($cds, function($a, $b) { 234 | return $a['DTPOSTED'] > $b['DTPOSTED']; 235 | }); 236 | foreach($cds as $cd) { 237 | $ofxdom->addTran($cd); 238 | } 239 | 240 | $cds_s = ""; 241 | $cds_e = ""; 242 | $items = $ofxdom->getTrans(); 243 | foreach ($items as $item) { 244 | $dtposted = $item->DTPOSTED; 245 | // DTSTART, DTENDを取得 246 | if($cds_s == "") $cds_s = $dtposted; 247 | $cds_e = $dtposted; 248 | } 249 | 250 | // DTSTARTとDTENDを設定する 251 | $ofxdom->setDateRange($cds_s, $cds_e); 252 | 253 | // 残高を処理 254 | $account["ledge_balamt"] = parse_amount($account["ledge_balamt"]); 255 | $ofxdom->setBalance(array( 256 | 'BALAMT' => $account["ledge_balamt"], 257 | 'DTASOF' => ENV_STR_DATE_TODAY . ENV_STR_OFX_TZ 258 | )); 259 | 260 | // FITIDを仕上げる 261 | $ofxdom->setFitid(); 262 | // XML DOMツリーを文字列に変換 263 | $xml = $ofxdom->getXML(); 264 | 265 | $resp["status"] = ENV_NUM_STATUS_SUCCESS; 266 | $resp["ofx"] = generate_ofx($resp["status"], $xml); 267 | 268 | // 実行時間(タイムアウト)を再設定する 269 | @set_time_limit(ENV_NUM_TIMEOUT); 270 | 271 | // ログアウトする 272 | $method = "GET"; 273 | $uris = $uris_old; 274 | $query = ""; 275 | $cookie = mufgcard_updatecookie($head, $cookie); 276 | list($head, $body) = mufgcard_http11($method, $uris["scheme"], $uris["host"], $uris["path"], $query, $cookie); 277 | 278 | // ログアウトする(NEWS+PLUS) 279 | $method = $method_mun; 280 | $uris = $uris_mun; 281 | $query = $query_mun; 282 | $cookie = $cookie_mun; 283 | list($head, $body) = mun_http11($method, $uris, $query, $cookie); 284 | } 285 | return $resp; 286 | 287 | // HTTP/1.1(NEWS+PLUS) 288 | function mun_http11($method, $uris, $query = "", $cookie = "") { 289 | $ret = "INVALID HOST"; 290 | if(preg_match("/\.cr\.mufg\.jp$/", $uris["host"]) > 0) $ret = http11(strtoupper($method), $uris["scheme"], $uris["host"], 0, $uris["path"], $query, "", $cookie); 291 | return explode("\r\n\r\n", $ret, 2); 292 | } 293 | 294 | function mun_update_cookie($head, $cookie) { 295 | return update_cookie(array("PHPSESSID", "session-srv", "m_cardBrand"), parse_header($head, "set-cookie"), $cookie); 296 | } 297 | 298 | // HTTP/1.1 299 | function mufgcard_http11($method, $protocol, $host, $page = "/", $query = "", $cookie = "") { 300 | $ret = "INVALID HOST"; 301 | if(preg_match("/\.mufgcard\.com$/", $host) > 0) $ret = http11(strtoupper($method), $protocol, $host, 0, $page, $query, "", $cookie); 302 | return explode("\r\n\r\n", $ret, 2); 303 | } 304 | 305 | function mufgcard_updatecookie($head, $cookie) { 306 | $ret = ""; 307 | $cookies = array(); 308 | 309 | $ckvs = explode(";", $cookie); 310 | foreach($ckvs as $ckv) { 311 | list($ck, $cv) = explode("=", $ckv, 2); 312 | $ck = trim($ck); 313 | $cv = trim($cv); 314 | if($ck != "" && $cv != "") $cookies[$ck] = $ck . "=" . $cv; 315 | } 316 | 317 | $cks = array("AS0[1-9]"); 318 | foreach($cks as $ck) { 319 | $c = preg_match_all("/[Ss][Ee][Tt]-[Cc][Oo][Oo][Kk][Ii][Ee][\s\t]*:[\s\t]*(" . $ck . ")=([^;\r\n]*)/", $head, $matches); 320 | for($i = 0; $i < $c; $i++) $cookies[$matches[1][$i]] = $matches[1][$i] . "=" . $matches[2][$i]; 321 | } 322 | $ret = implode("; ", $cookies); 323 | return $ret; 324 | } 325 | 326 | function mufgcard_parsedom($str) { 327 | // 明細表読み込み用DOMツリー作成 328 | $doc = new DOMDocument(); 329 | // 引き落とし月取得 330 | $month = (preg_match("/" .preg_quote("お支払日") . ".*?" . preg_quote("年") . "([0-9]+)" . preg_quote("月") . "/s", $str, $matches) > 0 ? $matches[1] : "00"); 331 | // の前のが,文字化けの原因となるため,削除 332 | $str = preg_replace('/<title>.*<\/title>/', '', $str); 333 | //   334 | $str = str_replace(" ", "", $str); 335 | // 文字エンコード変換 336 | // $str = mb_convert_encoding($str, 'UTF-8', 'SJIS'); 337 | // $str = str_replace('Shift_JIS','UTF-8',$str); 338 | // HTMLからDOMツリー作成 339 | $doc->loadHTML($str); 340 | $xpath = new DOMXPath($doc); 341 | // 明細表のテーブルを指定 342 | $tables = $xpath->query("//table[@class='mod-table font-x-small sp-font-normal transform']"); 343 | // 請求がない場合 344 | if($tables->length == 0) { 345 | return false; 346 | } 347 | $rows = $tables->item(0)->getElementsByTagName('tr'); 348 | 349 | $ret = ""; 350 | $cds = array(); 351 | $nrow = $rows->length; 352 | for($i=3; $i<$nrow; $i++) { 353 | $cd = array(); 354 | $row = $rows->item($i); 355 | $cols = $row->getElementsByTagName('dd'); 356 | // 利用明細でない行はスキップ 357 | if(empty($cols->item(0)->nodeValue)) continue; 358 | 359 | $cd["TRNTYPE"] = ENV_STR_OFX_TRNTYPE_CREDIT; 360 | 361 | // 日付を取得する 362 | $cd["DTPOSTED"] = parse_date(trim($cols->item(0)->nodeValue)); 363 | $cd["DTPOSTED"] .= ENV_STR_OFX_TZ; 364 | // トランザクション番号(請求月とデータ種別)を生成する 365 | $cd["FITID"] = sprintf("%02d0", $month); 366 | // 摘要を取得する 367 | $cd["NAME"] = $cols->item(1)->nodeValue; 368 | // 金額を取得する 369 | $cd["TRNAMT"] = (-1)*(double)parse_amount(trim($cols->item(4)->nodeValue)); 370 | 371 | array_push($cds, $cd); 372 | $cd_date = $cd["DTPOSTED"]; 373 | } 374 | return $cds; 375 | } 376 | ?> 377 | -------------------------------------------------------------------------------- /server/nanaco.inc: -------------------------------------------------------------------------------- 1 | <?php 2 | /* 3 | nanaco.inc: nanacoのHTMLよりOFXファイルを生成する 4 | Copyright (C) 2014-2017 OFFICE OUTERGUY. All rights reserved. 5 | mailto:contact@beatrek.com 6 | Licensed under the GNU AGPLv3. 7 | */ 8 | 9 | // ログイン情報を取得する 10 | $user = str_replace("-", "", $ofxforms["XCID"]); 11 | $pass = $ofxforms["LOGIN_PWD"]; 12 | 13 | $resp = array(); 14 | $ofx = ""; 15 | 16 | // 実行時間(タイムアウト)を再設定する 17 | @set_time_limit(ENV_NUM_TIMEOUT); 18 | 19 | // ホーム画面を取得する 20 | $method = "GET"; 21 | $uris = parse_uri($settings["home"]); 22 | $query = ""; 23 | $cookie = ""; 24 | list($head, $body) = nanaco_http11($method, $uris, $query, $cookie); 25 | 26 | // ログイン画面を取得する 27 | $as = parse_tag($body, "a"); 28 | $c = parse_tag_search($as, "innerHTML", "会員メニューログイン"); 29 | if($c != -1) { 30 | $method = "GET"; 31 | $uris = parse_uri($as[$c]["href"]); 32 | $query = ""; 33 | list($head, $body) = nanaco_http11($method, $uris, $query, $cookie); 34 | } 35 | 36 | // ログインする 37 | $forms = parse_tag($body, "form"); 38 | $c = parse_tag_search($forms, "id", "login_password"); 39 | if($c != -1) { 40 | $inputs = parse_tag($forms[$c]["innerHTML"], "input"); 41 | $queries = array(); 42 | foreach($inputs as $input) if($input["name"] != "") $queries[$input["name"]] = urlencode($input["name"]) . "=" . urlencode($input["value"]); 43 | $queries["XCID"] = "XCID=" . $user; 44 | $queries["LOGIN_PWD"] = "LOGIN_PWD=" . $pass; 45 | 46 | $method = $forms[$c]["method"]; 47 | $uris = parse_uri($forms[$c]["action"], $uris); 48 | $query = implode("&", $queries); 49 | $cookie = nanaco_update_cookie($head, $cookie); 50 | list($head, $body) = nanaco_http11($method, $uris, $query, $cookie); 51 | } 52 | 53 | if(strpos($body, "残高・履歴確認") === false) { 54 | // ログイン失敗の場合 55 | $resp["status"] = ENV_NUM_STATUS_FAILURE; 56 | $resp["method"] = $method; 57 | $resp["uri"] = $uris["scheme"] . "://" . $uris["host"] . $uris["path"]; 58 | $resp["query"] = $query; 59 | $resp["cookie"] = $cookie; 60 | $resp["head"] = $head; 61 | $resp["body"] = $body; 62 | $resp["ofx"] = generate_ofx($resp["status"]); 63 | } else { 64 | $account = array(); 65 | 66 | $account["acctname"] = $settings["name"]; 67 | 68 | // 支店番号を取得する 69 | $account["branchid"] = "0"; 70 | 71 | // 口座番号を取得する 72 | $account["acctid"] = $user; 73 | 74 | // 残高を取得する 75 | $account["balance"] = 0; 76 | $divs = parse_tag($body, "div", true); // 再帰的に取得する 77 | $c = parse_tag_search($divs, "class", "moneyBox"); 78 | if($c != -1) { 79 | $div2s = parse_tag($divs[$c]["innerHTML"], "div"); 80 | $c = parse_tag_search($div2s, "class", "fRight"); 81 | if($c != -1) $account["balance"] = parse_amount(strip_tags($div2s[$c]["innerHTML"])); 82 | } 83 | 84 | // 残高・履歴確認画面(1ページ目)を取得する 85 | $as = parse_tag($body, "a"); 86 | $c = parse_tag_search($as, "innerHTML", "残高・履歴確認"); 87 | if($c != -1) { 88 | $method = "GET"; 89 | $uris = parse_uri($as[$c]["href"], $uris); 90 | $query = ""; 91 | $cookie = nanaco_update_cookie($head, $cookie); 92 | list($head, $body) = nanaco_http11($method, $uris, $query, $cookie); 93 | } 94 | $account["details"] = array(); 95 | 96 | // 無限ループする 97 | while(true) { 98 | // 明細を取得する 99 | $tables = parse_tag($body, "table"); 100 | $c = parse_tag_search($tables, "id", "historyTbl"); 101 | if($c != -1) $account["details"] = array_merge(nanaco_get_details($tables[$c]["innerHTML"]), $account["details"]); 102 | 103 | // 残高・履歴確認画面(2ページ目以降)を取得する 104 | $as = parse_tag($body, "a"); 105 | $c = parse_tag_search($as, "innerHTML", " >>次へ"); 106 | if($c != -1) { 107 | $method = "GET"; 108 | $uris = parse_uri($as[$c]["href"], $uris); 109 | $query = ""; 110 | $cookie = nanaco_update_cookie($head, $cookie); 111 | list($head, $body) = nanaco_http11($method, $uris, $query, $cookie); 112 | } else { 113 | // 見つからない場合、ループを抜ける 114 | break; 115 | } 116 | } 117 | 118 | 119 | // 実行時間(タイムアウト)を再設定する 120 | @set_time_limit(ENV_NUM_TIMEOUT); 121 | 122 | // ログアウトする 123 | $as = parse_tag($body, "a"); 124 | $c = parse_tag_search($as, "innerHTML", "ログアウト"); 125 | if($c != -1) { 126 | $method = "GET"; 127 | $uris = parse_uri($as[$c]["href"], $uris); 128 | $query = ""; 129 | $cookie = nanaco_update_cookie($head, $cookie); 130 | list($head, $body) = nanaco_http11($method, $uris, $query, $cookie); 131 | } 132 | 133 | // 実行時間(タイムアウト)を再設定する 134 | @set_time_limit(ENV_NUM_TIMEOUT); 135 | 136 | $bankmsgsrsv1 = ""; 137 | $bankmsgsrsv1 .= "<BANKMSGSRSV1>"; 138 | $bankmsgsrsv1 .= "\r\n"; 139 | 140 | // 口座情報を取得する 141 | $bankmsgsrsv1 .= "<STMTTRNRS>"; 142 | $bankmsgsrsv1 .= "\r\n"; 143 | $bankmsgsrsv1 .= "<TRNUID>0</TRNUID>"; 144 | $bankmsgsrsv1 .= "\r\n"; 145 | $bankmsgsrsv1 .= "<STATUS><CODE>0</CODE><SEVERITY>INFO</SEVERITY></STATUS>"; 146 | $bankmsgsrsv1 .= "\r\n"; 147 | $bankmsgsrsv1 .= "<STMTRS>"; 148 | $bankmsgsrsv1 .= "\r\n"; 149 | $bankmsgsrsv1 .= "<CURDEF>" . ENV_STR_OFX_CURRENCY_JPY . "</CURDEF>"; 150 | $bankmsgsrsv1 .= "\r\n"; 151 | $bankmsgsrsv1 .= "<BANKACCTFROM>"; 152 | $bankmsgsrsv1 .= "<BANKID>" . $settings["code"] . "</BANKID>"; 153 | $bankmsgsrsv1 .= "<BRANCHID>" . $account["branchid"] . "</BRANCHID>"; 154 | $bankmsgsrsv1 .= "<ACCTID>" . $account["acctid"] . "</ACCTID>"; 155 | $bankmsgsrsv1 .= "<ACCTTYPE>" . ENV_STR_ACCTTYPE_CHECKING . "</ACCTTYPE>"; 156 | $bankmsgsrsv1 .= "</BANKACCTFROM>"; 157 | $bankmsgsrsv1 .= "\r\n"; 158 | $bankmsgsrsv1 .= nanaco_parse_details($account); 159 | $bankmsgsrsv1 .= "</STMTRS>"; 160 | $bankmsgsrsv1 .= "\r\n"; 161 | $bankmsgsrsv1 .= "</STMTTRNRS>"; 162 | $bankmsgsrsv1 .= "\r\n"; 163 | 164 | $bankmsgsrsv1 .= "</BANKMSGSRSV1>"; 165 | $bankmsgsrsv1 .= "\r\n"; 166 | 167 | // OFXファイルを出力する 168 | $resp["status"] = ENV_NUM_STATUS_SUCCESS; 169 | $resp["ofx"] = generate_ofx($resp["status"], $bankmsgsrsv1); 170 | } 171 | return $resp; 172 | 173 | // HTTP/1.1 174 | function nanaco_http11($method, $uris, $query = "", $cookie = "") { 175 | $ret = "INVALID HOST"; 176 | if(preg_match("/\.nanaco-net\.jp$/", $uris["host"]) > 0) $ret = http11(strtoupper($method), $uris["scheme"], $uris["host"], 0, $uris["path"], $query, "", $cookie); 177 | return explode("\r\n\r\n", $ret, 2); 178 | } 179 | 180 | function nanaco_update_cookie($head, $cookie) { 181 | return update_cookie(array("JSESSIONID", "BIGipServerPool_443_pc"), parse_header($head, "set-cookie"), $cookie); 182 | } 183 | 184 | function nanaco_get_details($body) { 185 | $rets = array(); 186 | $i = 0; 187 | $trs = parse_tag($body, "tr"); 188 | foreach(array_reverse($trs) as $tr) { 189 | $tds = parse_tag($tr["innerHTML"], "td"); 190 | if(count($tds) == 10) { 191 | // 日時を取得する 192 | $dt = explode("<br>", $tds[0]["innerHTML"]); 193 | 194 | // 取引種別、および場所を取得する 195 | $name = trim(strip_tags($tds[1]["innerHTML"])); 196 | $memo = trim(strip_tags($tds[9]["innerHTML"])); 197 | 198 | // nanacoチャージ額・支払額を取得する 199 | $am = explode("<br>", $tds[2]["innerHTML"]); 200 | $amount = (string)((integer)parse_amount(trim(strip_tags($am[0]))) + (integer)parse_amount(trim(strip_tags(str_replace(array("(", ")"), array("", ""), $am[1]))))); 201 | if($amount == "0") $amount = (string)(-1 * (integer)parse_amount(trim(strip_tags($tds[3]["innerHTML"])))); 202 | 203 | if($amount != "0") { 204 | $rets[$i]["date"] = parse_date(trim(strip_tags($dt[0]))); 205 | $rets[$i]["summary"] = $name; 206 | $rets[$i]["memo"] = $memo; 207 | $rets[$i]["amount"] = $amount; 208 | 209 | $i++; 210 | } 211 | } 212 | } 213 | 214 | return $rets; 215 | } 216 | 217 | function nanaco_parse_details($account) { 218 | $ret = ""; 219 | $cds = array(); 220 | $cd_date = ""; 221 | $cd_num = 0; 222 | $dtstart = ENV_STR_DATE_PASTDAY; 223 | foreach($account["details"] as $line) { 224 | if($dtstart > $line["date"]) $dtstart = $line["date"]; 225 | 226 | $cd = array(); 227 | $cd["TRNTYPE"] = ENV_STR_OFX_TRNTYPE_DIRECTDEBIT; 228 | 229 | // 日付を取得する 230 | $cd["DTPOSTED"] = $line["date"]; 231 | 232 | // 通番を生成する 233 | if($cd["DTPOSTED"] == $cd_date) $cd_num++; else $cd_num = 0; 234 | 235 | // トランザクション番号を生成する 236 | $cd["FITID"] = $cd["DTPOSTED"] . "0000000" . sprintf("%05d", $cd_num); 237 | 238 | // 摘要を取得する 239 | $cd["NAME"] = $line["summary"]; 240 | 241 | // 金額を取得する 242 | $cd["TRNAMT"] = parse_amount($line["amount"]); 243 | $cd["MEMO"] = ($line["memo"] != ""? $line["memo"]: ENV_STR_OFX_MEMO); 244 | 245 | array_push($cds, $cd); 246 | $cd_date = $cd["DTPOSTED"]; 247 | } 248 | // BANKTRANLIST 249 | $ret .= "<BANKTRANLIST>"; 250 | $ret .= "\r\n"; 251 | $ret .= "<DTSTART>" . $dtstart . ENV_STR_OFX_TZ . "</DTSTART>"; 252 | $ret .= "<DTEND>" . ENV_STR_DATE_TODAY . ENV_STR_OFX_TZ . "</DTEND>"; 253 | $ret .= "\r\n"; 254 | 255 | foreach($cds as $cd) { 256 | $ret .= "<STMTTRN>"; 257 | $ret .= "<TRNTYPE>" . $cd["TRNTYPE"] . "</TRNTYPE>"; 258 | $ret .= "<DTPOSTED>" . $cd["DTPOSTED"] . ENV_STR_OFX_TZ . "</DTPOSTED>"; 259 | $ret .= "<TRNAMT>" . $cd["TRNAMT"] . "</TRNAMT>"; 260 | $ret .= "<FITID>" . $cd["FITID"] . "</FITID>"; 261 | $ret .= "<NAME>" . $cd["NAME"] . "</NAME>"; 262 | $ret .= "<MEMO>" . $cd["MEMO"] . "</MEMO>"; 263 | $ret .= "</STMTTRN>"; 264 | $ret .= "\r\n"; 265 | } 266 | 267 | $ret .= "</BANKTRANLIST>"; 268 | $ret .= "\r\n"; 269 | $ret .= "<LEDGERBAL>"; 270 | $ret .= "<BALAMT>" . $account["balance"] . "</BALAMT>"; 271 | $ret .= "<DTASOF>" . ENV_STR_DATE_TODAY . ENV_STR_OFX_TZ . "</DTASOF>"; 272 | $ret .= "</LEDGERBAL>"; 273 | $ret .= "\r\n"; 274 | 275 | // 口座名称を出力する 276 | if($account["acctname"] != "") { 277 | $ret .= "<MKTGINFO>" . $account["acctname"] . "</MKTGINFO>"; 278 | $ret .= "\r\n"; 279 | } 280 | 281 | return $ret; 282 | } 283 | 284 | ?> 285 | -------------------------------------------------------------------------------- /server/netbk.inc: -------------------------------------------------------------------------------- 1 | <?php 2 | /* 3 | netbk.inc: 住信SBIネット銀行のCSVよりOFXファイルを生成する 4 | Copyright (C) 2012-2017 OFFICE OUTERGUY. All rights reserved. 5 | mailto:contact@beatrek.com 6 | Licensed under the GNU AGPLv3. 7 | */ 8 | 9 | // ログイン情報を取得する 10 | $user = $ofxforms["userName"]; 11 | $pass = $ofxforms["loginPwdSet"]; 12 | $token = urldecode($ofxforms["X-Token"]); 13 | 14 | $resp = array(); 15 | 16 | // 実行時間(タイムアウト)を再設定する 17 | @set_time_limit(ENV_NUM_TIMEOUT); 18 | 19 | // ホーム画面を取得する 20 | $method = "GET"; 21 | $uris = parse_uri($settings["home"]); 22 | $query = ""; 23 | $cookie = (ENV_BOOL_ADD_RISKBASE == true && $token != ""? $token: ""); 24 | list($head, $body) = netbk_http11($method, $uris, $query, $cookie); 25 | 26 | // リダイレクトする 27 | $retry = 0; 28 | while($retry++ < ENV_NUM_HTTP11_RETRY) { 29 | $locations = parse_header($head, "location"); 30 | if(count($locations) > 0) { 31 | $method = "GET"; 32 | $uris = parse_uri($locations[0], $uris); 33 | $query = ""; 34 | $cookie = netbk_update_cookie($head, $cookie); 35 | list($head, $body) = netbk_http11($method, $uris, $query, $cookie); 36 | } 37 | } 38 | 39 | // ログインする 40 | $forms = parse_tag($body, "form"); 41 | $c = parse_tag_search($forms, "name", "LoginForm"); 42 | if($c != -1) { 43 | $inputs = parse_tag($forms[$c]["innerHTML"], "input"); 44 | $queries = array(); 45 | foreach($inputs as $input) if($input["name"] != "") $queries[$input["name"]] = urlencode($input["name"]) . "=" . urlencode($input["value"]); 46 | $queries["userName"] = "userName=" . $user; 47 | $queries["loginPwdSet"] = "loginPwdSet=" . $pass; 48 | 49 | $method = $forms[$c]["method"]; 50 | $uris = parse_uri($forms[$c]["action"], $uris); 51 | $query = implode("&", $queries); 52 | $cookie = netbk_update_cookie($head, $cookie); 53 | list($head, $body) = netbk_http11($method, $uris, $query, $cookie); 54 | } 55 | 56 | // 重要なお知らせ画面が表示される場合、次の画面を取得する 57 | if(strpos($body, "銀行からの重要なお知らせ") !== false) { 58 | $forms = parse_tag($body, "form"); 59 | $c = parse_tag_search($forms, "name", "form0103_01_100"); 60 | if($c != -1) { 61 | $inputs = parse_tag($forms[$c]["innerHTML"], "input"); 62 | $queries = array(); 63 | foreach($inputs as $input) if($input["name"] != "") $queries[$input["name"]] = urlencode($input["name"]) . "=" . urlencode($input["value"]); 64 | if(isset($queries["imptNtcCheck"]) == true) unset($queries["imptNtcCheck"]); // 「確認しました」チェックボックスをオフにする 65 | 66 | $method = $forms[$c]["method"]; 67 | $uris = parse_uri($forms[$c]["action"], $uris); 68 | $query = implode("&", $queries); 69 | $cookie = netbk_update_cookie($head, $cookie); 70 | list($head, $body) = netbk_http11($method, $uris, $query, $cookie); 71 | } 72 | 73 | // リダイレクトする 74 | $forms = parse_tag($body, "form"); 75 | $c = parse_tag_search($forms, "name", "form0103_01_105"); 76 | if($c != -1) { 77 | $inputs = parse_tag($forms[$c]["innerHTML"], "input"); 78 | $queries = array(); 79 | foreach($inputs as $input) if($input["name"] != "") $queries[$input["name"]] = urlencode($input["name"]) . "=" . urlencode($input["value"]); 80 | 81 | $method = $forms[$c]["method"]; 82 | $uris = parse_uri($forms[$c]["action"], $uris); 83 | $query = implode("&", $queries); 84 | $cookie = netbk_update_cookie($head, $cookie); 85 | list($head, $body) = netbk_http11($method, $uris, $query, $cookie); 86 | } 87 | } 88 | 89 | if(strpos($body, "現在この取引はお取扱いできません") !== false) { 90 | // システムメンテナンス画面の場合 91 | $resp["status"] = ENV_NUM_STATUS_MAINTENANCE; 92 | $resp["method"] = $method; 93 | $resp["uri"] = $uris["scheme"] . "://" . $uris["host"] . $uris["path"]; 94 | $resp["query"] = $query; 95 | $resp["cookie"] = $cookie; 96 | $resp["head"] = $head; 97 | $resp["body"] = $body; 98 | $resp["ofx"] = generate_ofx($resp["status"]); 99 | } else if(strpos($body, "前回ログイン日時") === false) { 100 | // ログイン失敗の場合 101 | $resp["status"] = ENV_NUM_STATUS_FAILURE; 102 | $resp["method"] = $method; 103 | $resp["uri"] = $uris["scheme"] . "://" . $uris["host"] . $uris["path"]; 104 | $resp["query"] = $query; 105 | $resp["cookie"] = $cookie; 106 | $resp["head"] = $head; 107 | $resp["body"] = $body; 108 | $resp["ofx"] = generate_ofx($resp["status"]); 109 | } else { 110 | // 残高照会(口座別)画面を取得する 111 | $as = parse_tag($body, "a"); 112 | foreach($as as $a) if(parse_tag_search(parse_tag($a["innerHTML"], "span"), "innerHTML", "口座情報") != -1) { 113 | $method = "GET"; 114 | $uris = parse_uri($a["href"], $uris); 115 | $query = ""; 116 | $cookie = netbk_update_cookie($head, $cookie); 117 | list($head, $body) = netbk_http11($method, $uris, $query, $cookie); 118 | break; 119 | } 120 | 121 | // 口座情報を取得する 122 | if(preg_match("/([0-9]{3})\-([0-9]{7})/", $body, $matches) > 0) { 123 | $branchid = $matches[1]; 124 | $acctid = $matches[2]; 125 | } 126 | 127 | $accounts = array(); 128 | 129 | // 口座数を取得する 130 | $trs = parse_tag($body, "tr", true); // 再帰的に取得する 131 | foreach($trs as $tr) { 132 | $tds = parse_tag($tr["innerHTML"], "td"); 133 | if(count($tds) == 5) { 134 | $as = parse_tag($tds[4]["innerHTML"], "a"); 135 | foreach($as as $a) if(trim(strip_tags($a["innerHTML"])) == "明細" && preg_match("/.*?\/([0-9]{2})\/(01|21)\/001\/01/", $a["href"], $matches) > 0) { 136 | $accounts[$c]["acctname"] = str_replace(array("口座", " - "), array("", ENV_CHR_CONCATENATOR), trim(strip_tags($tds[0]["innerHTML"]))); 137 | $accounts[$c]["id"] = ($matches[2] == "01"? $matches[1]: "00"); // SBIハイブリッド預金を00とみなす 138 | $accounts[$c]["acctid"] = $matches[1]; // 01=代表口座 02-99=目的別口座 139 | $accounts[$c]["accttype"] = $matches[2]; // 01=円普通 21=SBIハイブリッド 140 | $accounts[$c]["page"] = $a["href"]; 141 | $c++; 142 | } 143 | } 144 | } 145 | 146 | // お客さま情報照会・変更画面を取得する 147 | $as = parse_tag($body, "a"); 148 | $c = parse_tag_search($as, "innerHTML", "お客さま情報照会・変更"); 149 | if($c != -1) { 150 | $method = "GET"; 151 | $uris = parse_uri($as[$c]["href"], $uris); 152 | $query = ""; 153 | $cookie = netbk_update_cookie($head, $cookie); 154 | list($head, $body) = netbk_http11($method, $uris, $query, $cookie); 155 | } 156 | 157 | // 支店名を取得する 158 | $otables = parse_tag($body, "table"); 159 | foreach($otables as $otable) { 160 | $tables = parse_tag($otable["innerHTML"], "table"); 161 | foreach($tables as $table) { 162 | $c = 0; 163 | $trs = parse_tag($table["innerHTML"], "tr"); 164 | foreach($trs as $tr) { 165 | $divs = parse_tag($tr["innerHTML"], "div"); 166 | if(count($divs) == 2 && trim(strip_tags($divs[0]["innerHTML"])) == "口座番号") { 167 | $bufs = explode(" ", preg_replace("/\s{2,}/", " ", str_replace(" ", "", trim(strip_tags($divs[1]["innerHTML"]))))); 168 | for($i = 0; $i < count($accounts); $i++) $accounts[$i]["acctname"] = implode(ENV_CHR_CONCATENATOR, array($settings["name"], $bufs[1], $accounts[$i]["acctname"])); 169 | } 170 | } 171 | } 172 | } 173 | 174 | $bankmsgsrsv1 = ""; 175 | $bankmsgsrsv1 .= "<BANKMSGSRSV1>"; 176 | $bankmsgsrsv1 .= "\r\n"; 177 | 178 | // 口座数分ループする 179 | foreach($accounts as $account) { 180 | // 実行時間(タイムアウト)を再設定する 181 | @set_time_limit(ENV_NUM_TIMEOUT); 182 | 183 | // 口座情報画面を取得する 184 | $method = "GET"; 185 | $uris = parse_uri($account["page"], $uris); 186 | $query = ""; 187 | $cookie = netbk_update_cookie($head, $cookie); 188 | list($head, $body) = netbk_http11($method, $uris, $query, $cookie); 189 | 190 | // 入出金明細画面を取得する 191 | $forms = parse_tag($body, "form"); 192 | $c = parse_tag_search($forms, "name", "form0202_01_100"); 193 | if($c != -1) { 194 | $inputs = parse_tag($forms[$c]["innerHTML"], "input"); 195 | $queries = array(); 196 | foreach($inputs as $input) if($input["name"] != "") $queries[$input["name"]] = urlencode($input["name"]) . "=" . urlencode($input["value"]); 197 | $selects = parse_tag($forms[$c]["innerHTML"], "select"); 198 | foreach($selects as $select) { 199 | $options = parse_tag($select["innerHTML"], "option"); 200 | foreach($options as $option) if($select["name"] != "" && $option["selected"] == "selected") $queries[$select["name"]] = urlencode($select["name"]) . "=" . urlencode($option["value"]); 201 | } 202 | $queries["termLink"] = "termLink=05"; // 期間指定 203 | $queries["term"] = "term=05"; // 期間指定 204 | $queries["acctBusPdCodeInput"] = "acctBusPdCodeInput=" . $account["acctid"] . $account["accttype"] . "001"; 205 | $queries["dsplyTrmSpcfdYearFrom"] = "dsplyTrmSpcfdYearFrom=" . substr(ENV_STR_DATE_PASTDAY, 0, 4); 206 | $queries["dsplyTrmSpcfdMonthFrom"] = "dsplyTrmSpcfdMonthFrom=" . substr(ENV_STR_DATE_PASTDAY, 4, 2); 207 | $queries["dsplyTrmSpcfdDayFrom"] = "dsplyTrmSpcfdDayFrom=" . substr(ENV_STR_DATE_PASTDAY, 6, 2); 208 | $queries["dsplyTrmSpcfdYearTo"] = "dsplyTrmSpcfdYearTo=" . substr(ENV_STR_DATE_TODAY, 0, 4); 209 | $queries["dsplyTrmSpcfdMonthTo"] = "dsplyTrmSpcfdMonthTo=" . substr(ENV_STR_DATE_TODAY, 4, 2); 210 | $queries["dsplyTrmSpcfdDayTo"] = "dsplyTrmSpcfdDayTo=" . substr(ENV_STR_DATE_TODAY, 6, 2); 211 | 212 | $method = $forms[$c]["method"]; 213 | $uris = parse_uri($forms[$c]["action"], $uris); 214 | $query = implode("&", $queries); 215 | $cookie = netbk_update_cookie($head, $cookie); 216 | list($head, $body) = netbk_http11($method, $uris, $query, $cookie); 217 | } 218 | 219 | // 明細が存在しない場合、選択中の口座の残高を取得する 220 | if(strpos($body, "表示可能な明細はございません") !== false) { 221 | $divs = parse_tag($body, "div", true); // 再帰的に取得する 222 | foreach($divs as $div) if($div["class"] == "tablef01M" && $div["innerHTML"] != "選択中の口座の残高") { 223 | $account["balamt"] = parse_amount(str_replace(" ", "", trim(strip_tags($div["innerHTML"])))); 224 | break; 225 | } 226 | } 227 | 228 | $body_old = $body; 229 | 230 | // CSVファイルをダウンロードする 231 | $forms = parse_tag($body, "form"); 232 | $c = parse_tag_search($forms, "name", "form0202_01_100"); 233 | if($c != -1) { 234 | $inputs = parse_tag($forms[$c]["innerHTML"], "input"); 235 | $queries = array(); 236 | foreach($inputs as $input) if($input["name"] != "") $queries[$input["name"]] = urlencode($input["name"]) . "=" . urlencode($input["value"]); 237 | $selects = parse_tag($forms[$c]["innerHTML"], "select"); 238 | foreach($selects as $select) { 239 | $options = parse_tag($select["innerHTML"], "option"); 240 | foreach($options as $option) if($select["name"] != "" && $option["selected"] == "selected") $queries[$select["name"]] = urlencode($select["name"]) . "=" . urlencode($option["value"]); 241 | } 242 | $queries["termLink"] = "termLink=05"; // 期間指定 243 | $queries["term"] = "term=05"; // 期間指定 244 | $queries["acctBusPdCodeInput"] = "acctBusPdCodeInput=" . $account["acctid"] . $account["accttype"] . "001"; 245 | $queries["dsplyTrmSpcfdYearFrom"] = "dsplyTrmSpcfdYearFrom=" . substr(ENV_STR_DATE_PASTDAY, 0, 4); 246 | $queries["dsplyTrmSpcfdMonthFrom"] = "dsplyTrmSpcfdMonthFrom=" . substr(ENV_STR_DATE_PASTDAY, 4, 2); 247 | $queries["dsplyTrmSpcfdDayFrom"] = "dsplyTrmSpcfdDayFrom=" . substr(ENV_STR_DATE_PASTDAY, 6, 2); 248 | $queries["dsplyTrmSpcfdYearTo"] = "dsplyTrmSpcfdYearTo=" . substr(ENV_STR_DATE_TODAY, 0, 4); 249 | $queries["dsplyTrmSpcfdMonthTo"] = "dsplyTrmSpcfdMonthTo=" . substr(ENV_STR_DATE_TODAY, 4, 2); 250 | $queries["dsplyTrmSpcfdDayTo"] = "dsplyTrmSpcfdDayTo=" . substr(ENV_STR_DATE_TODAY, 6, 2); 251 | $queries["_ActionID"] = "_ActionID=doCSVDownload"; // CSVダウンロード 252 | if(isset($queries["ACT_doShow"]) == true) unset($queries["ACT_doShow"]); 253 | 254 | $method = $forms[$c]["method"]; 255 | $uris = parse_uri($forms[$c]["action"], $uris); 256 | $query = implode("&", $queries); 257 | $cookie = netbk_update_cookie($head, $cookie); 258 | list($head, $body) = netbk_http11($method, $uris, $query, $cookie); 259 | 260 | if(strpos($head, "Content-Type: text/html") === false) { 261 | $bankmsgsrsv1 .= "<STMTTRNRS>"; 262 | $bankmsgsrsv1 .= "\r\n"; 263 | $bankmsgsrsv1 .= "<TRNUID>0</TRNUID>"; 264 | $bankmsgsrsv1 .= "\r\n"; 265 | $bankmsgsrsv1 .= "<STATUS><CODE>0</CODE><SEVERITY>INFO</SEVERITY></STATUS>"; 266 | $bankmsgsrsv1 .= "\r\n"; 267 | $bankmsgsrsv1 .= "<STMTRS>"; 268 | $bankmsgsrsv1 .= "\r\n"; 269 | $bankmsgsrsv1 .= "<CURDEF>" . ENV_STR_OFX_CURRENCY_JPY . "</CURDEF>"; 270 | $bankmsgsrsv1 .= "\r\n"; 271 | $bankmsgsrsv1 .= "<BANKACCTFROM>"; 272 | $bankmsgsrsv1 .= "<BANKID>" . $settings["code"] . "</BANKID>"; 273 | $bankmsgsrsv1 .= "<BRANCHID>" . $branchid . "</BRANCHID>"; 274 | $bankmsgsrsv1 .= "<ACCTID>" . $acctid . "-" . $account["id"] . "</ACCTID>"; 275 | $bankmsgsrsv1 .= "<ACCTTYPE>" . ENV_STR_ACCTTYPE_SAVINGS . "</ACCTTYPE>"; 276 | $bankmsgsrsv1 .= "</BANKACCTFROM>"; 277 | $bankmsgsrsv1 .= "\r\n"; 278 | $bankmsgsrsv1 .= netbk_parse_csv($body, $account); 279 | $bankmsgsrsv1 .= "</STMTRS>"; 280 | $bankmsgsrsv1 .= "\r\n"; 281 | $bankmsgsrsv1 .= "</STMTTRNRS>"; 282 | $bankmsgsrsv1 .= "\r\n"; 283 | } 284 | } 285 | 286 | $body = $body_old; 287 | } 288 | 289 | $bankmsgsrsv1 .= "</BANKMSGSRSV1>"; 290 | $bankmsgsrsv1 .= "\r\n"; 291 | 292 | // 実行時間(タイムアウト)を再設定する 293 | @set_time_limit(ENV_NUM_TIMEOUT); 294 | 295 | // ログアウトする 296 | $as = parse_tag($body, "a"); 297 | foreach($as as $a) if(parse_tag_search(parse_tag($a["innerHTML"], "img"), "alt", "ログアウト") != -1) { 298 | $method = "GET"; 299 | $uris = parse_uri($a["href"], $uris); 300 | $query = ""; 301 | $cookie = netbk_update_cookie($head, $cookie); 302 | list($head, $body) = netbk_http11($method, $uris, $query, $cookie); 303 | break; 304 | } 305 | 306 | if(ENV_BOOL_ADD_RISKBASE == true) { 307 | // 次回ログイン時に2段階認証を行わない 308 | $resp["token"] = netbk_get_token("termvalue", $cookie); 309 | } 310 | 311 | // OFXファイルを出力する 312 | $resp["status"] = ENV_NUM_STATUS_SUCCESS; 313 | if(strpos($bankmsgsrsv1, "<BANKTRANLIST>") === false) { 314 | // 明細が存在しない場合 315 | $resp["ofx"] = generate_ofx($resp["status"]); 316 | } else { 317 | // 明細が存在する場合 318 | $resp["ofx"] = generate_ofx($resp["status"], $bankmsgsrsv1); 319 | } 320 | } 321 | return $resp; 322 | 323 | // HTTP/1.1 324 | function netbk_http11($method, $uris, $query = "", $cookie = "") { 325 | $ret = "INVALID HOST"; 326 | if(preg_match("/\.netbk\.co\.jp$/", $uris["host"]) > 0) $ret = http11(strtoupper($method), $uris["scheme"], $uris["host"], 0, $uris["path"], $query, "", $cookie); 327 | return explode("\r\n\r\n", $ret, 2); 328 | } 329 | 330 | function netbk_update_cookie($head, $cookie) { 331 | return update_cookie(array("JSESSIONID", "termvalue"), parse_header($head, "set-cookie"), $cookie); 332 | } 333 | 334 | function netbk_get_token($name, $cookie) { 335 | $ret = ""; 336 | 337 | $kvs = explode(";", $cookie); 338 | foreach($kvs as $kv) { 339 | list($k, $v) = explode("=", $kv, 2); 340 | $k = trim($k); 341 | if($k == $name) { 342 | $ret = $k . "=" . trim($v); 343 | break; 344 | } 345 | } 346 | return $ret; 347 | } 348 | 349 | function netbk_parse_csv($str, $account) { 350 | $ret = ""; 351 | $lines = array_reverse(parse_csv(mb_convert_string($str))); 352 | $cds = array(); 353 | $cds_balamt = "0"; 354 | $cd_date = ""; 355 | $cd_num = 0; 356 | 357 | foreach($lines as $line) { 358 | $cd = array(); 359 | if(count($line) == 6 && $line[0] != "日付") { 360 | list($cd_name, $cd_dummy) = explode(ENV_CHR_SEPARATOR, str_replace(array("*", " "), array(ENV_CHR_SEPARATOR, ENV_CHR_SEPARATOR), $line[1]), 2); 361 | 362 | switch($cd_name) { 363 | case "振込": 364 | $cd["TRNTYPE"] = ENV_STR_OFX_TRNTYPE_DIRECTDEP; 365 | break; 366 | case "国税": 367 | case "地方税": 368 | $cd["TRNTYPE"] = ENV_STR_OFX_TRNTYPE_DEP; 369 | break; 370 | case "SBIハイブリッド預金": 371 | case "普通": 372 | $cd["TRNTYPE"] = ENV_STR_OFX_TRNTYPE_XFER; 373 | break; 374 | case "振替": 375 | $cd["TRNTYPE"] = ENV_STR_OFX_TRNTYPE_DEBIT; 376 | break; 377 | case "利息": 378 | $cd["TRNTYPE"] = ENV_STR_OFX_TRNTYPE_INT; 379 | break; 380 | case "ATM": 381 | $cd["TRNTYPE"] = ENV_STR_OFX_TRNTYPE_ATM; 382 | break; 383 | default: 384 | $cd["TRNTYPE"] = ENV_STR_OFX_TRNTYPE_OTHER; 385 | break; 386 | } 387 | 388 | // 日付を取得する 389 | $cd["DTPOSTED"] = parse_date($line[0]); 390 | 391 | // 通番を生成する 392 | if($cd["DTPOSTED"] == $cd_date) $cd_num++; else $cd_num = 0; 393 | 394 | // トランザクション番号を生成する 395 | $cd["FITID"] = $cd["DTPOSTED"] . sprintf("%04d", (integer)$account["accttype"]) . "000" . sprintf("%05d", $cd_num); 396 | 397 | // 摘要を取得する 398 | $cd["NAME"] = $line[1]; 399 | 400 | // 金額を取得する 401 | $cd["TRNAMT"] = (string)((double)parse_amount($line[3]) - (double)parse_amount($line[2])); 402 | 403 | // 残高を取得する 404 | $cds_balamt = (string)((double)parse_amount($line[4])); 405 | $cd["MEMO"] = $line[5]; 406 | 407 | array_push($cds, $cd); 408 | $cd_date = $cd["DTPOSTED"]; 409 | } 410 | } 411 | 412 | if($account["balamt"] != "") $cds_balamt = $account["balamt"]; 413 | 414 | // BANKTRANLIST 415 | $ret .= "<BANKTRANLIST>"; 416 | $ret .= "\r\n"; 417 | $ret .= "<DTSTART>" . ENV_STR_DATE_PASTDAY . ENV_STR_OFX_TZ . "</DTSTART>"; 418 | $ret .= "<DTEND>" . ENV_STR_DATE_TODAY . ENV_STR_OFX_TZ . "</DTEND>"; 419 | $ret .= "\r\n"; 420 | 421 | foreach($cds as $cd) { 422 | $ret .= "<STMTTRN>"; 423 | $ret .= "<TRNTYPE>" . $cd["TRNTYPE"] . "</TRNTYPE>"; 424 | $ret .= "<DTPOSTED>" . $cd["DTPOSTED"] . ENV_STR_OFX_TZ . "</DTPOSTED>"; 425 | $ret .= "<TRNAMT>" . $cd["TRNAMT"] . "</TRNAMT>"; 426 | $ret .= "<FITID>" . $cd["FITID"] . "</FITID>"; 427 | $ret .= "<NAME>" . $cd["NAME"] . "</NAME>"; 428 | $ret .= "<MEMO>" . $cd["MEMO"] . "</MEMO>"; 429 | $ret .= "</STMTTRN>"; 430 | $ret .= "\r\n"; 431 | } 432 | 433 | $ret .= "</BANKTRANLIST>"; 434 | $ret .= "\r\n"; 435 | $ret .= "<LEDGERBAL>"; 436 | $ret .= "<BALAMT>" . $cds_balamt . "</BALAMT>"; 437 | $ret .= "<DTASOF>" . ENV_STR_DATE_TODAY . ENV_STR_OFX_TZ . "</DTASOF>"; 438 | $ret .= "</LEDGERBAL>"; 439 | $ret .= "\r\n"; 440 | 441 | // 口座名称を出力する 442 | if($account["acctname"] != "") { 443 | $ret .= "<MKTGINFO>" . $account["acctname"] . "</MKTGINFO>"; 444 | $ret .= "\r\n"; 445 | } 446 | 447 | return $ret; 448 | } 449 | 450 | ?> 451 | -------------------------------------------------------------------------------- /server/rakutensec.inc: -------------------------------------------------------------------------------- 1 | <?php 2 | /* 3 | rakutensec.inc: 楽天証券のHTMLよりOFXファイルを生成する 4 | Copyright (C) 2012-2017 Hiromu2000. All Rights Reserved. 5 | mailto:hiromu2000@hotmail.com 6 | Licensed under the GNU AGPLv3. 7 | */ 8 | 9 | $resp = array(); 10 | $ofx = ""; 11 | 12 | // 実行時間(タイムアウト)を再設定する 13 | @set_time_limit(ENV_NUM_TIMEOUT); 14 | 15 | // ログイン画面を取得する 16 | $uris = parse_uri($settings["home"]); 17 | $query = ""; 18 | $cookie = ""; 19 | list($head, $body) = rakutensec_http11('GET', $uris, $query, $cookie); 20 | 21 | // ログインする 22 | $forms = parse_tag($body, "form"); 23 | $c = parse_tag_search($forms, "name", "loginform"); 24 | $inputs = parse_tag($forms[$c]["innerHTML"], "input"); 25 | $queries = array(); 26 | foreach($inputs as $input) { 27 | if($input["name"] != "") { 28 | $queries[$input["name"]] = urlencode($input["name"]) . "=" . urlencode($input["value"]); 29 | } 30 | } 31 | $queries["loginid"] .= $ofxforms["loginid"]; 32 | $queries["passwd"] .= $ofxforms["passwd"]; 33 | $queries["homeid"] = "homeid=HOME"; 34 | $uris = parse_uri('https://member.rakuten-sec.co.jp/bv/app/MhLogin.do', $uris); 35 | $query = implode("&", $queries); 36 | $cookie = rakutensec_update_cookie($head, $cookie); 37 | list($head, $body) = rakutensec_http11('POST', $uris, $query, $cookie); 38 | 39 | if (strpos($body, "未実装") !== false) { 40 | // システムメンテナンスの場合 41 | $resp["status"] = ENV_NUM_STATUS_MAINTENANCE; 42 | $resp["method"] = $method; 43 | $resp["uri"] = $uris["scheme"] . "://" . $uris["host"] . $uris["path"]; 44 | $resp["query"] = $query; 45 | $resp["cookie"] = $cookie; 46 | $resp["head"] = $head; 47 | $resp["body"] = $body; 48 | $resp["ofx"] = generate_ofx($resp["status"]); 49 | return $resp; 50 | } else if (!preg_match("/\"(\/app\/home\.do.*)\"/", $body, $matches)) { 51 | // ログイン失敗の場合 52 | $resp["status"] = ENV_NUM_STATUS_FAILURE; 53 | $resp["method"] = $method; 54 | $resp["uri"] = $uris["scheme"] . "://" . $uris["host"] . $uris["path"]; 55 | $resp["query"] = $query; 56 | $resp["cookie"] = $cookie; 57 | $resp["head"] = $head; 58 | $resp["body"] = $body; 59 | $resp["ofx"] = generate_ofx($resp["status"]); 60 | return $resp; 61 | } 62 | 63 | // リダイレクトし、ホーム画面のHTMLを取得する 64 | $uris = parse_uri($matches[1], $uris); 65 | preg_match('/(BV_SessionID=.*)\?/', $matches[1], $matches); 66 | $sessionid = $matches[1]; 67 | $query = ""; 68 | $cookie = rakutensec_update_cookie($head, $cookie); 69 | list($head, $body_home) = rakutensec_http11('GET', $uris, $query, $cookie); 70 | 71 | // 資産情報のHTMLを取得する 72 | $uris['path'] = '/app/async_change_home_balance_lst.do;' . $sessionid; 73 | $query = 'updateKbn=lastDay&openCode=1'; 74 | list($head, $body_balance) = rakutensec_http11('POST', $uris, $query, $cookie); 75 | 76 | // 入出金履歴のCSVを取得する 77 | // 一度ページ遷移をしないと、CSVをダウンロードできない模様 78 | $uris['path'] = '/app/ass_money_trans_lst.do;' . $sessionid; 79 | $query = 'eventType=init'; 80 | $cookie = rakutensec_update_cookie($head, $cookie); 81 | list($head, $body_trans) = rakutensec_http11('GET', $uris, $query, $cookie); 82 | 83 | $uris['path'] = '/app/ass_money_trans_lst_csv_output.do;' . $sessionid; 84 | $query = 'eventType=csv'; 85 | $cookie = rakutensec_update_cookie($head, $cookie); 86 | list($head, $body_trans) = rakutensec_http11('GET', $uris, $query, $cookie); 87 | 88 | // 取引履歴(国内株式)のCSVを取得する 89 | $uris['path'] = '/app/assTradJpLstCsvServlet;' . $sessionid; 90 | $queries = array(); 91 | $queries['searchFlg'] = 'searchFlg=0'; 92 | $queries['termCd'] = 'termCd=ALL'; 93 | $queries['trustKbn'] = 'trustKbn=A'; 94 | $queries['accCd'] = 'accCd=A'; 95 | foreach(array('yyyyFrom', 'mmFrom', 'ddFrom', 96 | 'yyyyTo', 'mmTo', 'ddTo', 97 | 'dscrCdNm', 98 | 'hiddenSearchFlag', 99 | 'hiddenYearFrom', 'hiddenMonthFrom', 'hiddenDayFrom', 100 | 'hiddenYearTo', 'hiddenMonthTo', 'hiddenDayTo', 101 | 'hiddenSpotTrustKbn', 'hiddenAccountCd', 'hiddenDscr', 102 | 'offsetRow') as $key) { 103 | $queries[$key] = $key . '='; 104 | } 105 | $query = implode("&", $queries); 106 | $cookie = rakutensec_update_cookie($head, $cookie); 107 | list($head, $body_trade_jp) = rakutensec_http11('GET', $uris, $query, $cookie); 108 | 109 | // 取引履歴(投資信託)のCSVを取得する 110 | $uris['path'] = '/app/assTradFuLstCsvServlet;' . $sessionid; 111 | unset($queries['trustKbn']); 112 | unset($queries['hiddenSpotTrustKbn']); 113 | $queries['hiddenTermCd'] = 'hiddenTermCd='; 114 | $query = implode("&", $queries); 115 | $cookie = rakutensec_update_cookie($head, $cookie); 116 | list($head, $body_trade_mf) = rakutensec_http11('GET', $uris, $query, $cookie); 117 | 118 | // 保有商品一覧(国内株式)のCSVを取得する 119 | $uris['path'] = '/app/ass_jp_possess_lst_csv_output.do;' . $sessionid; 120 | $query = 'eventType=csv'; 121 | $cookie = rakutensec_update_cookie($head, $cookie); 122 | list($head, $body_pos_jp) = rakutensec_http11('GET', $uris, $query, $cookie); 123 | 124 | // 保有商品一覧(投資信託)のCSVを取得する 125 | $uris['path'] = '/app/ass_fu_possess_lst_csv_output.do;' . $sessionid; 126 | $query = 'eventType=csv'; 127 | $cookie = rakutensec_update_cookie($head, $cookie); 128 | list($head, $body_pos_mf) = rakutensec_http11('GET', $uris, $query, $cookie); 129 | 130 | // ログアウトする 131 | $uris['path'] = '/app/logout.do;' . $sessionid; 132 | $query = ''; 133 | list($head, $body) = rakutensec_http11('GET', $uris, $query, $cookie); 134 | 135 | // リダイレクトする 136 | $uris['path'] = '/app/logout;' . $sessionid; 137 | list($head, $body) = rakutensec_http11('GET', $uris, $query, $cookie); 138 | 139 | /********** ページ遷移ここまで **********/ 140 | 141 | // ホーム画面のHTMLを処理し、部店-お客様コード(口座番号)を取得する 142 | if (preg_match('/[0-9]{3}-[0-9]{6}/', $body_home, $matches)) $acctid = $matches[0]; 143 | 144 | // DOMツリーを生成 145 | $ofxdom = new ofxDOM("INVSTMT", $settings["name"]); 146 | $ofxdom->setAcctfrom(array( 147 | "BROKERID" => $settings["code"], 148 | "ACCTID" => $acctid 149 | )); 150 | 151 | // 資産情報のHTMLを処理する 152 | $divs = parse_tag($body_balance, 'div'); 153 | $c = parse_tag_search($divs, 'id', 'balance_data_actual_data'); 154 | $tds = parse_tag($divs[$c]['innerHTML'], 'td'); 155 | preg_match('/[0-9,]+/', $tds[21]['innerHTML'], $matches); 156 | $availcash = parse_amount($matches[0]); 157 | 158 | // 残高を設定 159 | $ofxdom->setBalance(array( 160 | 'AVAILCASH' => $availcash, 161 | 'MARGINBALANCE' => $availcash, 162 | 'SHORTBALANCE' => 0 163 | )); 164 | 165 | // 入出力履歴のCSVを処理する 166 | $body_trans = mb_convert_encoding($body_trans, "UTF-8", "sjis-win"); 167 | $rows = parse_csv($body_trans); 168 | array_splice($rows, 0, 4); // ヘッダー行等最初の4行(+空行1行)をスキップする 169 | foreach ($rows as $row) { 170 | $cd = array(); 171 | $date = date_parse($row[0]); 172 | $cd['DTPOSTED'] = sprintf("%d%02d%02d", $date['year'], $date['month'], $date['day']); 173 | $cd['DTPOSTED'] .= ENV_STR_OFX_TZ; 174 | if (preg_match('/[0-9,]+/', $row[1]) > 0) { // 入金 175 | $cd['TRNAMT'] = $row[1]; 176 | } else { // 出金 177 | $cd['TRNAMT'] = '-' . $row[2]; 178 | } 179 | $cd["TRNTYPE"] = ENV_STR_OFX_TRNTYPE_DIRECTDEP; 180 | $cd['NAME'] = $row[3] . ' ' . $row[4]; 181 | // トランザクション番号(請求月とデータ種別)を生成する 182 | $cd["FITID"] = '000'; 183 | 184 | // 入出力履歴をDOMに書き込む 185 | if (strtotime(ENV_STR_DATE_PASTDAY) <= strtotime($row[0]) && strtotime($row[0]) <= strtotime(ENV_STR_DATE_TODAY)) { 186 | $ofxdom->addTran($cd); 187 | } else { 188 | break; 189 | } 190 | } 191 | 192 | // DTSTARTとDTENDを設定する 193 | $ofxdom->setDateRange(ENV_STR_DATE_PASTDAY . ENV_STR_OFX_TZ, ENV_STR_DATE_TODAY . ENV_STR_OFX_TZ); 194 | 195 | // 取引履歴(国内株式)のCSVを処理する 196 | $body_trade_jp = mb_convert_encoding($body_trade_jp, "UTF-8", "sjis-win"); 197 | $rows = parse_csv($body_trade_jp); 198 | array_shift($rows); // ヘッダー行をスキップする 199 | foreach ($rows as $row) { 200 | $ct = array(); 201 | $ct['CATEGORY'] = ENV_STR_OFX_STOCK; 202 | $date = date_parse($row[0]); 203 | $ct['DTTRADE'] = sprintf("%d%02d%02d000000", $date['year'], $date['month'], $date['day']) 204 | . ENV_STR_OFX_TZ; 205 | $ct['UNIQUEID'] = $row[2]; 206 | $ct['SECNAME'] = $row[3]; 207 | $ct['UNIQUEIDTYPE'] = ENV_STR_OFX_CODE_STOCK; 208 | $ct['UNITS'] = (int)parse_amount($row[10]); 209 | $ct['UNITPRICE'] = parse_amount($row[11]); 210 | $ct['FEES'] = (int)parse_amount($row[12]); 211 | $ct['TAXES'] = (int)parse_amount($row[13]); 212 | $ct['COMMISSION'] = (int)parse_amount($row[14]); 213 | $ct['TOTAL'] = (int)parse_amount($row[16]); 214 | $ct['SUBACCTSEC'] = ENV_STR_OFX_CASH; 215 | $ct['SUBACCTFUND'] = ENV_STR_OFX_CASH; 216 | $ct['FITID'] = '000'; 217 | if (preg_match('/買付/', $row[7]) > 0) { 218 | $ct['BUYTYPE'] = ENV_STR_OFX_BUY; 219 | $ct['TOTAL'] *= -1; 220 | } else { 221 | $ct['BUYTYPE'] = ENV_STR_OFX_SELL; 222 | $ct['UNITS'] *= -1; 223 | } 224 | 225 | if (strtotime(ENV_STR_DATE_PASTDAY) <= strtotime($row[0]) && strtotime($row[0]) <= strtotime(ENV_STR_DATE_TODAY)) { 226 | $ofxdom->addTrade($ct); 227 | } 228 | } 229 | 230 | // 取引履歴(投資信託)のCSVを処理する 231 | $body_trade_mf = mb_convert_encoding($body_trade_mf, "UTF-8", "sjis-win"); 232 | $rows = parse_csv($body_trade_mf); 233 | array_shift($rows); // ヘッダー行をスキップする 234 | foreach ($rows as $row) { 235 | $ct = array(); 236 | $ct['CATEGORY'] = ENV_STR_OFX_FUND; 237 | $date = date_parse($row[0]); 238 | $ct['DTTRADE'] = sprintf("%d%02d%02d", $date['year'], $date['month'], $date['day']) 239 | . ENV_STR_OFX_TZ; 240 | $ct['UNIQUEID'] = md5($row[2]); 241 | $ct['SECNAME'] = $row[2]; 242 | $ct['UNIQUEIDTYPE'] = ENV_STR_OFX_CODE_FUND; 243 | $ct['UNITS'] = (int)parse_amount($row[7]); 244 | $ct['UNITPRICE'] = parse_amount($row[8]); 245 | //$ct['FEES'] = (int)parse_amount($row[9]); 246 | // total = units * unitprice + (commission + fee + taxes)とするため、feeを0にする 247 | $ct['FEES'] = 0; 248 | $ct['TAXES'] = 0; 249 | $ct['COMMISSION'] = 0; 250 | $ct['TOTAL'] = (int)parse_amount($row[10]); 251 | $ct['SUBACCTSEC'] = ENV_STR_OFX_CASH; 252 | $ct['FITID'] = '000'; 253 | switch ($row[5]) { 254 | case '買付': 255 | $ct['BUYTYPE'] = ENV_STR_OFX_BUY; 256 | $ct['SUBACCTFUND'] = ENV_STR_OFX_CASH; 257 | $ct['TOTAL'] *= -1; 258 | break; 259 | case '解約': 260 | $ct['BUYTYPE'] = ENV_STR_OFX_SELL; 261 | $ct['SUBACCTFUND'] = ENV_STR_OFX_CASH; 262 | $ct['UNITS'] *= -1; 263 | break; 264 | case '再投資': 265 | default: 266 | $ct['BUYTYPE'] = ENV_STR_OFX_REINVEST; 267 | $ct['INCOMETYPE'] = ENV_STR_OFX_TRNTYPE_INT; 268 | $ct['TOTAL'] *= -1; 269 | break; 270 | } 271 | 272 | if (strtotime(ENV_STR_DATE_PASTDAY) <= strtotime($row[0]) && strtotime($row[0]) <= strtotime(ENV_STR_DATE_TODAY)) { 273 | $ofxdom->addTrade($ct); 274 | } 275 | } 276 | 277 | // 保有商品一覧(国内株式)のCSVを処理する 278 | $body_pos_jp = mb_convert_encoding($body_pos_jp, "UTF-8", "sjis-win"); 279 | $rows = parse_csv($body_pos_jp); 280 | array_shift($rows); // ヘッダー行をスキップする 281 | foreach ($rows as $row) { 282 | $cl = array(); 283 | $cl['CATEGORY'] = ENV_STR_OFX_STOCK; 284 | $cl['HELDINACCT'] = ENV_STR_OFX_CASH; 285 | $cl['POSTYPE'] = 'LONG'; 286 | $cl['DTPRICEASOF'] = ENV_STR_DATE_TODAY; 287 | $cl['UNIQUEIDTYPE'] = ENV_STR_OFX_CODE_STOCK; 288 | $cl['UNIQUEID'] = $row[1]; 289 | $cl['SECNAME'] = $row[2]; 290 | $cl['UNITS'] = (int)parse_amount($row[3]); 291 | $cl['UNITPRICE'] = parse_amount($row[6]); 292 | $cl['MKTVAL'] = (int)parse_amount($row[7]); 293 | $cl['MEMO'] = (int)parse_amount($row[8]); 294 | 295 | $ofxdom->addPos($cl); 296 | $ofxdom->addSec($cl); 297 | } 298 | 299 | // 保有商品一覧(投資信託)のCSVを処理する 300 | $body_pos_mf = mb_convert_encoding($body_pos_mf, "UTF-8", "sjis-win"); 301 | $rows = parse_csv($body_pos_mf); 302 | array_shift($rows); // ヘッダー行をスキップする 303 | foreach ($rows as $row) { 304 | $cl = array(); 305 | $cl['CATEGORY'] = ENV_STR_OFX_FUND; 306 | $cl['HELDINACCT'] = ENV_STR_OFX_CASH; 307 | $cl['POSTYPE'] = 'LONG'; 308 | $cl['DTPRICEASOF'] = ENV_STR_DATE_TODAY; 309 | $cl['UNIQUEID'] = md5($row[2]); 310 | $cl['UNIQUEIDTYPE'] = ENV_STR_OFX_CODE_FUND; 311 | $cl['SECNAME'] = $row[2]; 312 | $cl['UNITS'] = (int)parse_amount($row[4]); 313 | $cl['UNITPRICE'] = 1; 314 | $cl['MKTVAL'] = (int)parse_amount($row[14]); 315 | $cl['MEMO'] = $row[10]; 316 | 317 | $ofxdom->addPos($cl); 318 | $ofxdom->addSec($cl); 319 | } 320 | 321 | // FITIDを仕上げる 322 | $ofxdom->setFitid(); 323 | // XML DOMツリーを文字列に変換 324 | $xml = $ofxdom->getXML(); 325 | $resp["status"] = ENV_NUM_STATUS_SUCCESS; 326 | $resp["ofx"] = generate_ofx($mode, $xml); 327 | 328 | return $resp; 329 | 330 | // HTTP/1.1 331 | function rakutensec_http11($method, $uris, $query = "", $cookie = "") { 332 | $ret = "INVALID HOST"; 333 | if(preg_match("/\.rakuten-sec\.co\.jp$/", $uris["host"]) > 0) $ret = http11(strtoupper($method), $uris["scheme"], $uris["host"], 0, $uris["path"], $query, "", $cookie); 334 | return explode("\r\n\r\n", $ret, 2); 335 | } 336 | function rakutensec_update_cookie($head, $cookie) { 337 | return update_cookie(array( 338 | "Rg_sec", 339 | "checkTk", 340 | ), parse_header($head, "set-cookie"), $cookie); 341 | } 342 | ?> 343 | -------------------------------------------------------------------------------- /server/saisoncard.inc: -------------------------------------------------------------------------------- 1 | <?php 2 | /* 3 | saisoncard.inc: セゾンカードのCSVよりOFXファイルを生成する 4 | Copyright (C) 2012-2017 OFFICE OUTERGUY. All rights reserved. 5 | mailto:contact@beatrek.com 6 | Licensed under the GNU AGPLv3. 7 | */ 8 | 9 | // ログイン情報を取得する 10 | $user = $ofxforms["inputId"]; 11 | $pass = $ofxforms["inputPassword"]; 12 | $auth = urlencode(mb_convert_encoding(urldecode($ofxforms["secretAnswer"]), "Shift_JIS", "UTF-8")); 13 | $sesscookie = $ofxforms["sesscookie"]; 14 | $accesskey = $ofxforms["accesskey"]; 15 | 16 | $resp = array(); 17 | $sid = 0; 18 | $method = ""; 19 | $query = ""; 20 | $cookie = ""; 21 | $head = ""; 22 | $body = ""; 23 | 24 | if($sesscookie != "") list($cookie, $dummy) = explode("\t", sess_decode($sesscookie)); 25 | if($accesskey != "") { 26 | list($ssid, $method, $uri, $query, $pass, $dummy) = explode("\t", sess_decode($accesskey), 6); 27 | $sid = (integer)$ssid; 28 | } 29 | 30 | // 実行時間(タイムアウト)を再設定する 31 | @set_time_limit(ENV_NUM_TIMEOUT); 32 | 33 | if($sid == 0) { 34 | // ホーム画面を取得する 35 | $method = "GET"; 36 | $uris = parse_uri($settings["home"]); 37 | $query = ""; 38 | $cookie = ""; 39 | list($head, $body) = saisoncard_http11($method, $uris, $query, $cookie); 40 | 41 | // ログイン画面を取得する 42 | $as = parse_tag($body, "a", true); // 再帰的に取得する 43 | foreach($as as $a) if(parse_tag_search(parse_tag($a["innerHTML"], "img"), "alt", "ログインはこちらから") != -1) { 44 | $method = "GET"; 45 | $uris = parse_uri($a["href"], $uris); 46 | $query = ""; 47 | $cookie = saisoncard_update_cookie($head, $cookie); 48 | list($head, $body) = saisoncard_http11($method, $uris, $query, $cookie); 49 | break; 50 | } 51 | 52 | // ログインする 53 | $forms = parse_tag($body, "form"); 54 | $c = parse_tag_search($forms, "name", "_USA01Form"); 55 | if($c != -1) { 56 | $inputs = parse_tag($forms[$c]["innerHTML"], "input"); 57 | $queries = array(); 58 | foreach($inputs as $input) if($input["name"] != "") $queries[$input["name"]] = urlencode($input["name"]) . "=" . urlencode($input["value"]); 59 | $queries["inputId"] = "inputId=" . $user; 60 | $queries["inputPassword"] = "inputPassword=" . $pass; 61 | if(isset($queries["inputIdCheckBox"]) == true) unset($queries["inputIdCheckBox"]); 62 | 63 | $method = $forms[$c]["method"]; 64 | $uris = parse_uri($forms[$c]["action"], $uris); 65 | $query = implode("&", $queries); 66 | $cookie = saisoncard_update_cookie($head, $cookie); 67 | list($head, $body) = saisoncard_http11($method, $uris, $query, $cookie); 68 | } 69 | } 70 | 71 | if(strpos($body, "秘密の質問によるご本人様確認") !== false) { 72 | // 秘密の答えを入力する 73 | $tds = parse_tag($body, "td"); 74 | $shitsumon = ""; 75 | foreach($tds as $td) if($td["class"] == "td-01") { 76 | $shitsumon = trim(strip_tags($td["innerHTML"])); 77 | break; 78 | } 79 | 80 | $forms = parse_tag($body, "form"); 81 | $c = parse_tag_search($forms, "name", "_UST00Form"); 82 | if($c != -1) { 83 | $inputs = parse_tag($forms[$c]["innerHTML"], "input"); 84 | $queries = array(); 85 | foreach($inputs as $input) if($input["name"] != "") $queries[$input["name"]] = urlencode($input["name"]) . "=" . urlencode($input["value"]); 86 | $queries["secretAnswer"] = "secretAnswer="; 87 | 88 | $method = $forms[$c]["method"]; 89 | $uris = parse_uri($forms[$c]["action"], $uris); 90 | $query = implode("&", $queries); 91 | $cookie = saisoncard_update_cookie($head, $cookie); 92 | } 93 | 94 | // セッションを退避する 95 | $sid = 1; 96 | $head = ""; 97 | $body = ""; 98 | } else if($sid == 1) { 99 | // セッションを復元する 100 | $sid = 0; 101 | $uris = parse_uri($uri); 102 | $query = str_replace("secretAnswer=", "secretAnswer=" . $auth, $query); 103 | list($head, $body) = saisoncard_http11($method, $uris, $query, $cookie); 104 | } 105 | 106 | if($sid > 0) { 107 | // セッションを引き継ぐ 108 | $resp["status"] = ENV_NUM_STATUS_ADDITION; 109 | $resp["aid"] = "secretAnswer"; 110 | $resp["additional"] = $shitsumon; 111 | $resp["sid"] = $sid; 112 | $resp["sesscookie"] = sess_encode(implode("\t", array($cookie, ENV_STR_SESSION_PADDING))); 113 | $resp["accesskey"] = sess_encode(implode("\t", array((string)$sid, $method, $uris["scheme"] . "://" . $uris["host"] . $uris["path"], $query, $pass, ENV_STR_SESSION_PADDING))); 114 | 115 | $mfachallengetrnrs = ""; 116 | $mfachallengetrnrs .= "<MFACHALLENGETRNRS>"; 117 | $mfachallengetrnrs .= "<MFACHALLENGERS>"; 118 | $mfachallengetrnrs .= "<MFACHALLENGE>"; 119 | $mfachallengetrnrs .= "<MFAPHRASEID>" . $resp["aid"] . "</MFAPHRASEID>"; 120 | $mfachallengetrnrs .= "<MFAPHRASELABEL>" . $resp["additional"] . "</MFAPHRASELABEL>"; 121 | $mfachallengetrnrs .= "</MFACHALLENGE>"; 122 | $mfachallengetrnrs .= "</MFACHALLENGERS>"; 123 | $mfachallengetrnrs .= "</MFACHALLENGETRNRS>"; 124 | 125 | $resp["ofx"] = generate_ofx($resp["status"], $mfachallengetrnrs, $resp["sesscookie"], $resp["accesskey"]); 126 | } else if(strpos($body, "秘密の質問設定") !== false) { 127 | // ログイン後の画面が通常と異なる場合 128 | $resp["status"] = ENV_NUM_STATUS_CAUTION; 129 | $resp["method"] = $method; 130 | $resp["uri"] = $uris["scheme"] . "://" . $uris["host"] . $uris["path"]; 131 | $resp["query"] = $query; 132 | $resp["cookie"] = $cookie; 133 | $resp["head"] = $head; 134 | $resp["body"] = $body; 135 | $resp["ofx"] = generate_ofx($resp["status"]); 136 | } else if(strpos($body, "メンテナンス中") !== false || strpos($body, "サービスがご利用いただけません") !== false) { 137 | // システムメンテナンス画面の場合 138 | $resp["status"] = ENV_NUM_STATUS_MAINTENANCE; 139 | $resp["method"] = $method; 140 | $resp["uri"] = $uris["scheme"] . "://" . $uris["host"] . $uris["path"]; 141 | $resp["query"] = $query; 142 | $resp["cookie"] = $cookie; 143 | $resp["head"] = $head; 144 | $resp["body"] = $body; 145 | $resp["ofx"] = generate_ofx($resp["status"]); 146 | } else if(strpos($body, "前回ログイン") === false) { 147 | // ログイン失敗の場合 148 | $resp["status"] = ENV_NUM_STATUS_FAILURE; 149 | $resp["method"] = $method; 150 | $resp["uri"] = $uris["scheme"] . "://" . $uris["host"] . $uris["path"]; 151 | $resp["query"] = $query; 152 | $resp["cookie"] = $cookie; 153 | $resp["head"] = $head; 154 | $resp["body"] = $body; 155 | $resp["ofx"] = generate_ofx($resp["status"]); 156 | } else { 157 | $account = array(); 158 | $account["id"] = 0; 159 | 160 | // 実行時間(タイムアウト)を再設定する 161 | @set_time_limit(ENV_NUM_TIMEOUT); 162 | 163 | // Netアンサー情報照会画面を取得する 164 | $as = parse_tag($body, "a"); 165 | foreach($as as $a) if(parse_tag_search(parse_tag($a["innerHTML"], "img"), "alt", "Netアンサー登録内容変更 NetアンサーID、パスワード、 メールアドレスなど ") != -1) { 166 | $method = "GET"; 167 | $uris = parse_uri($a["href"], $uris); 168 | $query = ""; 169 | $cookie = saisoncard_update_cookie($head, $cookie); 170 | list($head, $body) = saisoncard_http11($method, $uris, $query, $cookie); 171 | break; 172 | } 173 | 174 | $tds = parse_tag($body, "td", true); // 再帰的に取得する 175 | $bufs = array(); 176 | foreach($tds as $td) if($td["class"] == "td-01") array_push($bufs, trim(strip_tags($td["innerHTML"]))); 177 | if(count($bufs) >= 2) { 178 | // カード名称を取得する 179 | $account["acctname"] = implode(ENV_CHR_CONCATENATOR, array($settings["name"], $bufs[0])); 180 | $account["name"] = $settings["name"]; 181 | 182 | // カード番号を取得する 183 | $account["acctid"] = $bufs[2]; 184 | } 185 | 186 | // ご利用明細画面を取得する 187 | $as = parse_tag($body, "a"); 188 | $c = parse_tag_search($as, "innerHTML", "ご利用明細照会"); 189 | if($c != -1) { 190 | $method = "GET"; 191 | $uris = parse_uri($as[$c]["href"], $uris); 192 | $query = ""; 193 | $cookie = saisoncard_update_cookie($head, $cookie); 194 | list($head, $body) = saisoncard_http11($method, $uris, $query, $cookie); 195 | } 196 | 197 | // 最新の請求月を取得する(お支払日は4日であると仮定する) 198 | $c = preg_match_all("/([0-9]{1,2})" . preg_quote("月お支払分") . "/", $body, $matches); 199 | if($c > 0) { 200 | $matches[1][0] = sprintf("%02d", (integer)$matches[1][0]); 201 | $account["paydate"] = (date("m") <= $matches[1][0]? date("Y"): (string)((integer)date("Y") + 1)) . $matches[1][0] . "04"; 202 | } 203 | 204 | $body_old = $body; 205 | 206 | // CSVファイルをダウンロードする 207 | $as = parse_tag($body, "a"); 208 | foreach($as as $a) if(parse_tag_search(parse_tag($a["innerHTML"], "img"), "alt", "CSVダウンロード") != -1) { 209 | $method = "GET"; 210 | $uris = parse_uri($a["href"], $uris); 211 | $query = ""; 212 | $cookie = saisoncard_update_cookie($head, $cookie); 213 | list($head, $body) = saisoncard_http11($method, $uris, $query, $cookie); 214 | break; 215 | } 216 | 217 | if(strpos($head, "Content-Type: text/html") === false) { 218 | $creditcardmsgsrsv1 = ""; 219 | $creditcardmsgsrsv1 .= "<CREDITCARDMSGSRSV1>"; 220 | $creditcardmsgsrsv1 .= "\r\n"; 221 | 222 | $creditcardmsgsrsv1 .= "<CCSTMTTRNRS>"; 223 | $creditcardmsgsrsv1 .= "\r\n"; 224 | $creditcardmsgsrsv1 .= "<TRNUID>0</TRNUID>"; 225 | $creditcardmsgsrsv1 .= "\r\n"; 226 | $creditcardmsgsrsv1 .= "<STATUS><CODE>0</CODE><SEVERITY>INFO</SEVERITY></STATUS>"; 227 | $creditcardmsgsrsv1 .= "\r\n"; 228 | $creditcardmsgsrsv1 .= "<CCSTMTRS>"; 229 | $creditcardmsgsrsv1 .= "\r\n"; 230 | $creditcardmsgsrsv1 .= "<CURDEF>" . ENV_STR_OFX_CURRENCY_JPY . "</CURDEF>"; 231 | $creditcardmsgsrsv1 .= "\r\n"; 232 | $creditcardmsgsrsv1 .= "<CCACCTFROM>"; 233 | $creditcardmsgsrsv1 .= "<ACCTID>" . $account["acctid"] . "</ACCTID>"; 234 | $creditcardmsgsrsv1 .= "</CCACCTFROM>"; 235 | $creditcardmsgsrsv1 .= "\r\n"; 236 | $creditcardmsgsrsv1 .= saisoncard_parse_csv($body, $account); 237 | $creditcardmsgsrsv1 .= "</CCSTMTRS>"; 238 | $creditcardmsgsrsv1 .= "\r\n"; 239 | $creditcardmsgsrsv1 .= "</CCSTMTTRNRS>"; 240 | $creditcardmsgsrsv1 .= "\r\n"; 241 | 242 | $creditcardmsgsrsv1 .= "</CREDITCARDMSGSRSV1>"; 243 | $creditcardmsgsrsv1 .= "\r\n"; 244 | } 245 | 246 | $body = $body_old; 247 | 248 | // 実行時間(タイムアウト)を再設定する 249 | @set_time_limit(ENV_NUM_TIMEOUT); 250 | 251 | // ログアウトする 252 | $as = parse_tag($body, "a"); 253 | foreach($as as $a) if(parse_tag_search(parse_tag($a["innerHTML"], "img"), "alt", "ログアウト") != -1) { 254 | $method = "GET"; 255 | $uris = parse_uri($a["href"], $uris); 256 | $query = ""; 257 | $cookie = saisoncard_update_cookie($head, $cookie); 258 | list($head, $body) = saisoncard_http11($method, $uris, $query, $cookie); 259 | break; 260 | } 261 | 262 | // OFXファイルを出力する 263 | $resp["status"] = ENV_NUM_STATUS_SUCCESS; 264 | if(strpos($creditcardmsgsrsv1, "<BANKTRANLIST>") === false) { 265 | // 明細が存在しない場合 266 | $resp["ofx"] = generate_ofx($resp["status"]); 267 | } else { 268 | // 明細が存在する場合 269 | $resp["ofx"] = generate_ofx($resp["status"], $creditcardmsgsrsv1); 270 | } 271 | } 272 | return $resp; 273 | 274 | // HTTP/1.1 275 | function saisoncard_http11($method, $uris, $query = "", $cookie = "") { 276 | $ret = "INVALID HOST"; 277 | if(preg_match("/\.saisoncard\.co\.jp$/", $uris["host"]) > 0) $ret = http11(strtoupper($method), $uris["scheme"], $uris["host"], 0, $uris["path"], $query, "", $cookie); 278 | return explode("\r\n\r\n", $ret, 2); 279 | } 280 | 281 | function saisoncard_update_cookie($head, $cookie) { 282 | return update_cookie(array("JSESSIONID"), parse_header($head, "set-cookie"), $cookie); 283 | } 284 | 285 | function saisoncard_parse_csv($str, $account) { 286 | $ret = ""; 287 | $lines = parse_csv(mb_convert_string($str)); 288 | $cds = array(); 289 | $cds_balamt = "0"; 290 | $cds_paydate = $account["paydate"]; 291 | $cds_s = ""; 292 | $cds_e = ""; 293 | $cd_date = ""; 294 | $cd_num = 0; 295 | $ledge_balamt = 0; 296 | 297 | foreach($lines as $line) { 298 | $cd = array(); 299 | 300 | if(count($line) == 2) { 301 | switch($line[0]) { 302 | case "お支払日": 303 | $cds_paydate = parse_date($line[1]); 304 | break; 305 | case "今回ご請求額": 306 | $cds_balamt = (string)(double)parse_amount($line[1]); 307 | $ledge_balamt = (double)$cds_balamt; 308 | break; 309 | case "カード名称": 310 | default: 311 | break; 312 | } 313 | } else if(count($line) == 7 && $line[0] != "利用日") { 314 | // PAYMENT固定とする 315 | $cd["TRNTYPE"] = ENV_STR_OFX_TRNTYPE_PAYMENT; 316 | 317 | // 日付を取得する 318 | $cd["DTPOSTED"] = parse_date($line[0]); 319 | if($cds_s == "") $cds_s = $cd["DTPOSTED"]; 320 | $cds_e = $cd["DTPOSTED"]; 321 | 322 | // 通番を生成する 323 | if($cd["DTPOSTED"] == $cd_date) $cd_num++; else $cd_num = 0; 324 | 325 | // トランザクション番号を生成する 326 | $cd["FITID"] = $cd["DTPOSTED"] . sprintf("%04d", $account["id"]) . substr($account["paydate"], 4, 2) . "0" . sprintf("%05d", $cd_num); 327 | 328 | // 摘要を取得する 329 | $cd["NAME"] = $line[1]; 330 | 331 | // 金額を取得する 332 | $cd["TRNAMT"] = (string)(-1 * (double)parse_amount($line[5])); 333 | $ledge_balamt += (double)$cd["TRNAMT"]; 334 | 335 | // 残高を取得する 336 | $cd["MEMO"] = ($line[6] != ""? $line[6]: ENV_STR_OFX_MEMO); 337 | 338 | array_push($cds, $cd); 339 | $cd_date = $cd["DTPOSTED"]; 340 | } 341 | } 342 | 343 | if($cds_s == "") $cds_s = ENV_STR_DATE_TODAY; 344 | if($cds_e == "") $cds_e = ENV_STR_DATE_TODAY; 345 | if($cds_s > $cds_e) $cds_e = $cds_s; 346 | 347 | // クレジットカード支払請求を明細に追加する 348 | $i = count($cds); 349 | $cds[$i]["DTPOSTED"] = $cds_paydate; 350 | $cds[$i]["NAME"] = $account["name"]; 351 | $cds[$i]["MEMO"] = ENV_STR_OFX_MEMO; 352 | $cds[$i]["TRNAMT"] = $cds_balamt; 353 | $cds[$i]["TRNTYPE"] = ENV_STR_OFX_TRNTYPE_DIRECTDEBIT; 354 | $cds[$i]["FITID"] = $cds[$i]["DTPOSTED"] . sprintf("%04d", $account["id"]) . substr($account["paydate"], 4, 2) . "100000"; 355 | 356 | // BANKTRANLIST 357 | $ret .= "<BANKTRANLIST>"; 358 | $ret .= "\r\n"; 359 | $ret .= "<DTSTART>" . $cds_s . ENV_STR_OFX_TZ . "</DTSTART>"; 360 | $ret .= "<DTEND>" . $cds_e . ENV_STR_OFX_TZ . "</DTEND>"; 361 | $ret .= "\r\n"; 362 | 363 | foreach($cds as $cd) { 364 | $ret .= "<STMTTRN>"; 365 | $ret .= "<TRNTYPE>" . $cd["TRNTYPE"] . "</TRNTYPE>"; 366 | $ret .= "<DTPOSTED>" . $cd["DTPOSTED"] . ENV_STR_OFX_TZ . "</DTPOSTED>"; 367 | $ret .= "<TRNAMT>" . $cd["TRNAMT"] . "</TRNAMT>"; 368 | $ret .= "<FITID>" . $cd["FITID"] . "</FITID>"; 369 | $ret .= "<NAME>" . $cd["NAME"] . "</NAME>"; 370 | $ret .= "<MEMO>" . $cd["MEMO"] . "</MEMO>"; 371 | $ret .= "</STMTTRN>"; 372 | $ret .= "\r\n"; 373 | } 374 | 375 | $ret .= "</BANKTRANLIST>"; 376 | $ret .= "\r\n"; 377 | 378 | // 支払後残高を出力する 379 | $ret .= "<LEDGERBAL>"; 380 | $ret .= "<BALAMT>" . (string)$ledge_balamt . "</BALAMT>"; 381 | $ret .= "<DTASOF>" . ENV_STR_DATE_TODAY . ENV_STR_OFX_TZ . "</DTASOF>"; 382 | $ret .= "</LEDGERBAL>"; 383 | $ret .= "\r\n"; 384 | 385 | // カード名称を出力する 386 | if($account["acctname"] != "") { 387 | $ret .= "<MKTGINFO>" . $account["acctname"] . "</MKTGINFO>"; 388 | $ret .= "\r\n"; 389 | } 390 | 391 | return $ret; 392 | } 393 | 394 | ?> 395 | -------------------------------------------------------------------------------- /server/smbccard.inc: -------------------------------------------------------------------------------- 1 | <?php 2 | /* 3 | smbccard.inc: 三井住友カードのCSVよりOFXファイルを生成する 4 | Copyright (C) 2012-2017 OFFICE OUTERGUY. All rights reserved. 5 | mailto:contact@beatrek.com 6 | Licensed under the GNU AGPLv3. 7 | */ 8 | 9 | // ログイン情報を取得する 10 | $user = $ofxforms["userid"]; 11 | $pass = $ofxforms["password"]; 12 | 13 | $resp = array(); 14 | 15 | // 実行時間(タイムアウト)を再設定する 16 | @set_time_limit(ENV_NUM_TIMEOUT); 17 | 18 | // ホーム画面を取得する 19 | $method = "GET"; 20 | $uris = parse_uri($settings["home"]); 21 | $query = ""; 22 | $cookie = ""; 23 | list($head, $body) = smbccard_http11($method, $uris, $query, $cookie); 24 | 25 | // リダイレクトする 26 | $retry = 0; 27 | while($retry++ < ENV_NUM_HTTP11_RETRY) { 28 | $locations = parse_header($head, "location"); 29 | if(count($locations) > 0) { 30 | $method = "GET"; 31 | $uris = parse_uri($locations[0], $uris); 32 | $query = ""; 33 | $cookie = smbccard_update_cookie($head, $cookie); 34 | list($head, $body) = smbccard_http11($method, $uris, $query, $cookie); 35 | } 36 | } 37 | 38 | // ログイン画面を取得する 39 | $as = parse_tag($body, "a"); 40 | 41 | foreach($as as $a) if(strip_tags($a["innerHTML"]) == "カード会員の方 Vpassログイン") { 42 | $method = "GET"; 43 | $uris = parse_uri($a["href"], $uris); 44 | $query = ""; 45 | $cookie = smbccard_update_cookie($head, $cookie); 46 | list($head, $body) = smbccard_http11($method, $uris, $query, $cookie); 47 | break; 48 | } 49 | 50 | // ログインする 51 | $forms = parse_tag($body, "form"); 52 | $c = parse_tag_search($forms, "name", "InForm"); 53 | if($c != -1) { 54 | $inputs = parse_tag($forms[$c]["innerHTML"], "input"); 55 | $queries = array(); 56 | foreach($inputs as $input) if($input["name"] != "") $queries[$input["name"]] = urlencode($input["name"]) . "=" . urlencode($input["value"]); 57 | $queries["userid"] = "userid=" . $user; 58 | $queries["password"] = "password=" . $pass; 59 | 60 | $method = $forms[$c]["method"]; 61 | $uris = parse_uri($forms[$c]["action"], $uris); 62 | $query = implode("&", $queries); 63 | $cookie = smbccard_update_cookie($head, $cookie); 64 | list($head, $body) = smbccard_http11($method, $uris, $query, $cookie); 65 | } 66 | 67 | // リダイレクトする 68 | $retry = 0; 69 | while($retry++ < ENV_NUM_HTTP11_RETRY) { 70 | $locations = parse_header($head, "location"); 71 | if(count($locations) > 0) { 72 | $method = "GET"; 73 | $uris = parse_uri($locations[0], $uris); 74 | $query = ""; 75 | $cookie = smbccard_update_cookie($head, $cookie); 76 | list($head, $body) = smbccard_http11($method, $uris, $query, $cookie); 77 | } 78 | } 79 | 80 | if(strpos($body, "システムメンテナンス中") !== false) { 81 | // システムメンテナンス画面の場合 82 | $resp["status"] = ENV_NUM_STATUS_MAINTENANCE; 83 | $resp["method"] = $method; 84 | $resp["uri"] = $uris["scheme"] . "://" . $uris["host"] . $uris["path"]; 85 | $resp["query"] = $query; 86 | $resp["cookie"] = $cookie; 87 | $resp["head"] = $head; 88 | $resp["body"] = $body; 89 | $resp["ofx"] = generate_ofx($resp["status"]); 90 | } else if(strpos($body, "IDまたはパスワードが無効となっております") !== false) { 91 | // ログイン後の画面が通常と異なる場合 92 | $resp["status"] = ENV_NUM_STATUS_CAUTION; 93 | $resp["method"] = $method; 94 | $resp["uri"] = $uris["scheme"] . "://" . $uris["host"] . $uris["path"]; 95 | $resp["query"] = $query; 96 | $resp["cookie"] = $cookie; 97 | $resp["head"] = $head; 98 | $resp["body"] = $body; 99 | $resp["ofx"] = generate_ofx($resp["status"]); 100 | } else if(strpos($body, "ログイン中") === false) { 101 | // ログイン失敗の場合 102 | $resp["status"] = ENV_NUM_STATUS_FAILURE; 103 | $resp["method"] = $method; 104 | $resp["uri"] = $uris["scheme"] . "://" . $uris["host"] . $uris["path"]; 105 | $resp["query"] = $query; 106 | $resp["cookie"] = $cookie; 107 | $resp["head"] = $head; 108 | $resp["body"] = $body; 109 | $resp["ofx"] = generate_ofx($resp["status"]); 110 | } else { 111 | $account = array(); 112 | $account["flag"] = false; 113 | $account["paydate"] = "00000000"; 114 | $account["balamt"] = "0"; 115 | 116 | // 実行時間(タイムアウト)を再設定する 117 | @set_time_limit(ENV_NUM_TIMEOUT); 118 | 119 | if(strpos($body, "パスワード変更に関するお願い") !== false) { 120 | // パスワード変更に関するお願い画面の場合、ログイン中 カード会員の方TOP画面を取得する 121 | $as = parse_tag($body, "a"); 122 | foreach($as as $a) if(parse_tag_search(parse_tag($a["innerHTML"], "img"), "alt", "ログイン中 カード会員の方TOP") != -1) { 123 | $method = "GET"; 124 | $uris = parse_uri($a["href"], $uris); 125 | $query = ""; 126 | $cookie = smbccard_update_cookie($head, $cookie); 127 | list($head, $body) = smbccard_http11($method, $uris, $query, $cookie); 128 | break; 129 | } 130 | } 131 | 132 | // カード名称を取得する 133 | $fonts = parse_tag($body, "font"); 134 | $c = parse_tag_search($fonts, "color", "#006633"); 135 | if($c != -1) { 136 | $account["acctname"] = implode(ENV_CHR_CONCATENATOR, array($settings["name"], trim(strip_tags($fonts[$c]["innerHTML"])))); 137 | $account["name"] = $settings["name"]; 138 | } 139 | 140 | // ご利用明細画面を取得する 141 | // 最新月の確定済みの明細が0件の場合、カード番号を取得できないため、デフォルトで表示される(最新月以前で明細が1件以上ある月の)ご利用明細画面を取得する 142 | $as = parse_tag($body, "a"); 143 | foreach($as as $a) if(parse_tag_search(parse_tag($a["innerHTML"], "img"), "alt", "ご利用明細を見る") != -1) { 144 | $method = "GET"; 145 | $uris = parse_uri($a["href"], $uris); 146 | $query = ""; 147 | $cookie = smbccard_update_cookie($head, $cookie); 148 | list($head, $body) = smbccard_http11($method, $uris, $query, $cookie); 149 | break; 150 | } 151 | 152 | // カード番号を取得する 153 | $trs = parse_tag($body, "tr", true); // 再帰的に取得する 154 | foreach($trs as $tr) { 155 | $tds = parse_tag($tr["innerHTML"], "td"); 156 | if(count($tds) == 2 && $tds[0]["class"] == "sdbc2") { 157 | $account["acctid"] = trim(strip_tags($tds[0]["innerHTML"])); 158 | break; 159 | } 160 | } 161 | if($account["acctid"] == "") $account["acctid"] = $user; 162 | 163 | // お支払いについて画面を取得する 164 | $as = parse_tag($body, "a"); 165 | foreach($as as $a) if(parse_tag_search(parse_tag($a["innerHTML"], "img"), "alt", "お支払いについて") != -1) { 166 | $method = "GET"; 167 | $uris = parse_uri($a["href"], $uris); 168 | $query = ""; 169 | $cookie = smbccard_update_cookie($head, $cookie); 170 | list($head, $body) = smbccard_http11($method, $uris, $query, $cookie); 171 | break; 172 | } 173 | 174 | // お支払い金額照会画面を取得する 175 | $as = parse_tag($body, "a"); 176 | $c = parse_tag_search($as, "innerHTML", "お支払い金額照会"); 177 | if($c != -1) { 178 | $method = "GET"; 179 | $uris = parse_uri($as[$c]["href"], $uris); 180 | $query = ""; 181 | $cookie = smbccard_update_cookie($head, $cookie); 182 | list($head, $body) = smbccard_http11($method, $uris, $query, $cookie); 183 | } 184 | 185 | // (最新月の確定済みの)ご利用明細画面を取得する 186 | $trs = parse_tag($body, "tr", true); // 再帰的に取得する 187 | $uri = ""; 188 | foreach($trs as $tr) { 189 | $tds = parse_tag($tr["innerHTML"], "td"); 190 | if(count($tds) == 3 && strpos($tds[0]["innerHTML"], "確定分") !== false) { 191 | // お支払日を取得する 192 | if(preg_match("/([0-9]{1,2})" . preg_quote("月") . "([0-9]{1,2})" . preg_quote("日お支払い 確定分") . "/", trim(strip_tags($tds[0]["innerHTML"])), $matches) > 0) { 193 | $matches[1] = sprintf("%02d", (integer)$matches[1]); 194 | $matches[2] = sprintf("%02d", (integer)$matches[2]); 195 | $account["paydate"] = (date("m") <= $matches[1]? date("Y"): (string)((integer)date("Y") + 1)) . $matches[1] . $matches[2]; 196 | } 197 | 198 | // お支払合計額を取得する 199 | $account["balamt"] = parse_amount(strip_tags($tds[1]["innerHTML"])); 200 | 201 | $as = parse_tag($tds[2]["innerHTML"], "a"); 202 | if(count($as) > 0 && parse_tag_search(parse_tag($as[0]["innerHTML"], "img"), "alt", "") != -1) $uri = $as[0]["href"]; 203 | // breakしない 204 | } 205 | } 206 | if($uri != "") { 207 | $method = "GET"; 208 | $uris = parse_uri($uri, $uris); 209 | $query = ""; 210 | $cookie = smbccard_update_cookie($head, $cookie); 211 | list($head, $body) = smbccard_http11($method, $uris, $query, $cookie); 212 | } 213 | 214 | $body_old = $body; 215 | 216 | // CSVファイルをダウンロードする 217 | $as = parse_tag($body, "a"); 218 | $c = parse_tag_search($as, "innerHTML", "CSV形式で保存"); 219 | if($c != -1) { 220 | $method = "GET"; 221 | $uris = parse_uri($as[$c]["href"], $uris); 222 | $query = ""; 223 | $cookie = smbccard_update_cookie($head, $cookie); 224 | list($head, $body) = smbccard_http11($method, $uris, $query, $cookie); 225 | } 226 | 227 | $creditcardmsgsrsv1 = ""; 228 | $creditcardmsgsrsv1 .= "<CREDITCARDMSGSRSV1>"; 229 | $creditcardmsgsrsv1 .= "\r\n"; 230 | 231 | $creditcardmsgsrsv1 .= "<CCSTMTTRNRS>"; 232 | $creditcardmsgsrsv1 .= "\r\n"; 233 | $creditcardmsgsrsv1 .= "<TRNUID>0</TRNUID>"; 234 | $creditcardmsgsrsv1 .= "\r\n"; 235 | $creditcardmsgsrsv1 .= "<STATUS><CODE>0</CODE><SEVERITY>INFO</SEVERITY></STATUS>"; 236 | $creditcardmsgsrsv1 .= "\r\n"; 237 | $creditcardmsgsrsv1 .= "<CCSTMTRS>"; 238 | $creditcardmsgsrsv1 .= "\r\n"; 239 | $creditcardmsgsrsv1 .= "<CURDEF>" . ENV_STR_OFX_CURRENCY_JPY . "</CURDEF>"; 240 | $creditcardmsgsrsv1 .= "\r\n"; 241 | $creditcardmsgsrsv1 .= "<CCACCTFROM>"; 242 | $creditcardmsgsrsv1 .= "<ACCTID>" . $account["acctid"] . "</ACCTID>"; 243 | $creditcardmsgsrsv1 .= "</CCACCTFROM>"; 244 | $creditcardmsgsrsv1 .= "\r\n"; 245 | $creditcardmsgsrsv1 .= smbccard_parse_csv($body, $account); // 0固定?(要検討) 246 | $creditcardmsgsrsv1 .= "</CCSTMTRS>"; 247 | $creditcardmsgsrsv1 .= "\r\n"; 248 | $creditcardmsgsrsv1 .= "</CCSTMTTRNRS>"; 249 | $creditcardmsgsrsv1 .= "\r\n"; 250 | 251 | $creditcardmsgsrsv1 .= "</CREDITCARDMSGSRSV1>"; 252 | $creditcardmsgsrsv1 .= "\r\n"; 253 | 254 | $body = $body_old; 255 | 256 | // 実行時間(タイムアウト)を再設定する 257 | @set_time_limit(ENV_NUM_TIMEOUT); 258 | 259 | // ログアウトする 260 | $as = parse_tag($body, "a"); 261 | foreach($as as $a) if(parse_tag_search(parse_tag($a["innerHTML"], "img"), "alt", "ログアウト") != -1) { 262 | $method = "GET"; 263 | $uris = parse_uri($a["href"], $uris); 264 | $query = ""; 265 | $cookie = smbccard_update_cookie($head, $cookie); 266 | list($head, $body) = smbccard_http11($method, $uris, $query, $cookie); 267 | break; 268 | } 269 | 270 | // リダイレクトする 271 | $retry = 0; 272 | while($retry++ < ENV_NUM_HTTP11_RETRY) { 273 | $locations = parse_header($head, "location"); 274 | if(count($locations) > 0) { 275 | $method = "GET"; 276 | $uris = parse_uri($locations[0], $uris); 277 | $query = ""; 278 | $cookie = smbccard_update_cookie($head, $cookie); 279 | list($head, $body) = smbccard_http11($method, $uris, $query, $cookie); 280 | } 281 | } 282 | 283 | // OFXファイルを出力する 284 | $resp["status"] = ENV_NUM_STATUS_SUCCESS; 285 | if(strpos($creditcardmsgsrsv1, "<BANKTRANLIST>") === false) { 286 | // 明細が存在しない場合 287 | $resp["ofx"] = generate_ofx($resp["status"]); 288 | } else { 289 | // 明細が存在する場合 290 | $resp["ofx"] = generate_ofx($resp["status"], $creditcardmsgsrsv1); 291 | } 292 | } 293 | return $resp; 294 | 295 | // HTTP/1.1 296 | function smbccard_http11($method, $uris, $query = "", $cookie = "") { 297 | $ret = "INVALID HOST"; 298 | if(preg_match("/\.smbc-card\.com$/", $uris["host"]) > 0) $ret = http11(strtoupper($method), $uris["scheme"], $uris["host"], 0, $uris["path"], $query, "", $cookie); 299 | return explode("\r\n\r\n", $ret, 2); 300 | } 301 | 302 | function smbccard_update_cookie($head, $cookie) { 303 | return update_cookie(array("vpasssession", "pass", "ch"), parse_header($head, "set-cookie"), $cookie); 304 | } 305 | 306 | function smbccard_parse_csv($str, $account) { 307 | $ret = ""; 308 | $lines = array_reverse(parse_csv(mb_convert_string($str))); 309 | $cds = array(); 310 | $cds_balamt = "0"; 311 | $cds_s = ""; 312 | $cds_e = ""; 313 | $cd_date = ""; 314 | $cd_num = 0; 315 | 316 | // 今回お支払金額を取得する 317 | $ledge_balamt = (double)$account["balamt"]; 318 | 319 | foreach($lines as $line) { 320 | $cd = array(); 321 | 322 | if(count($line) == 7 && $line[0] != "") { 323 | // WEB明細書CSVの場合 324 | 325 | // PAYMENT固定とする 326 | $cd["TRNTYPE"] = ENV_STR_OFX_TRNTYPE_PAYMENT; 327 | 328 | // 日付を取得する 329 | $cd["DTPOSTED"] = parse_date($line[0]); 330 | if($cds_s == "") $cds_s = $cd["DTPOSTED"]; 331 | $cds_e = $cd["DTPOSTED"]; 332 | 333 | // 通番を生成する 334 | if($cd["DTPOSTED"] == $cd_date) $cd_num++; else $cd_num = 0; 335 | 336 | // トランザクション番号を生成する 337 | $cd["FITID"] = $cd["DTPOSTED"] . "0000" . substr($account["paydate"], 4, 2) . "0" . sprintf("%05d", $cd_num); 338 | 339 | // 摘要を取得する 340 | $cd["NAME"] = $line[1]; 341 | 342 | // 金額を取得する 343 | $cd["TRNAMT"] = (string)(-1 * (double)parse_amount($line[5])); 344 | $ledge_balamt += (double)$cd["TRNAMT"]; 345 | 346 | // 残高を取得する 347 | $cd["MEMO"] = ($line[7] != ""? $line[7]: ENV_STR_OFX_MEMO); 348 | 349 | array_push($cds, $cd); 350 | $cd_date = $cd["DTPOSTED"]; 351 | } else if(count($line) == 13) { 352 | // ご利用明細照会CSVの場合 353 | 354 | // PAYMENT固定とする 355 | $cd["TRNTYPE"] = ENV_STR_OFX_TRNTYPE_PAYMENT; 356 | 357 | // 日付を取得する 358 | $cd["DTPOSTED"] = parse_date($line[0]); 359 | if($cds_s == "") $cds_s = $cd["DTPOSTED"]; 360 | $cds_e = $cd["DTPOSTED"]; 361 | 362 | // 通番を生成する 363 | if($cd["DTPOSTED"] == $cd_date) $cd_num++; else $cd_num = 0; 364 | 365 | // トランザクション番号を生成する 366 | $cd["FITID"] = $cd["DTPOSTED"] . "0000" . substr($account["paydate"], 4, 2) . "0" . sprintf("%05d", $cd_num); 367 | 368 | // 摘要を取得する 369 | $cd["NAME"] = $line[1]; 370 | 371 | // 金額を取得する 372 | $cd["TRNAMT"] = (string)(-1 * (double)parse_amount($line[6])); 373 | $ledge_balamt += (double)$cd["TRNAMT"]; 374 | 375 | // 残高を取得する 376 | $cd["MEMO"] = ($line[3] != ""? $line[3]: ENV_STR_OFX_MEMO); 377 | 378 | array_push($cds, $cd); 379 | $cd_date = $cd["DTPOSTED"]; 380 | } 381 | } 382 | 383 | if($cds_s == "") $cds_s = ENV_STR_DATE_TODAY; 384 | if($cds_e == "") $cds_e = ENV_STR_DATE_TODAY; 385 | if($cds_s > $cds_e) $cds_e = $cds_s; 386 | 387 | // クレジットカード支払請求を明細に追加する 388 | $i = count($cds); 389 | $cds[$i]["DTPOSTED"] = $account["paydate"]; 390 | $cds[$i]["NAME"] = $account["name"]; 391 | $cds[$i]["MEMO"] = ENV_STR_OFX_MEMO; 392 | $cds[$i]["TRNAMT"] = $account["balamt"]; 393 | $cds[$i]["TRNTYPE"] = ENV_STR_OFX_TRNTYPE_DIRECTDEBIT; 394 | $cds[$i]["FITID"] = $cds[$i]["DTPOSTED"] . "0000" . substr($account["paydate"], 4, 2) . "100000"; 395 | 396 | // BANKTRANLIST 397 | $ret .= "<BANKTRANLIST>"; 398 | $ret .= "\r\n"; 399 | $ret .= "<DTSTART>" . $cds_s . ENV_STR_OFX_TZ . "</DTSTART>"; 400 | $ret .= "<DTEND>" . $cds_e . ENV_STR_OFX_TZ . "</DTEND>"; 401 | $ret .= "\r\n"; 402 | 403 | foreach($cds as $cd) { 404 | $ret .= "<STMTTRN>"; 405 | $ret .= "<TRNTYPE>" . $cd["TRNTYPE"] . "</TRNTYPE>"; 406 | $ret .= "<DTPOSTED>" . $cd["DTPOSTED"] . ENV_STR_OFX_TZ . "</DTPOSTED>"; 407 | $ret .= "<TRNAMT>" . $cd["TRNAMT"] . "</TRNAMT>"; 408 | $ret .= "<FITID>" . $cd["FITID"] . "</FITID>"; 409 | $ret .= "<NAME>" . $cd["NAME"] . "</NAME>"; 410 | $ret .= "<MEMO>" . $cd["MEMO"] . "</MEMO>"; 411 | $ret .= "</STMTTRN>"; 412 | $ret .= "\r\n"; 413 | } 414 | 415 | $ret .= "</BANKTRANLIST>"; 416 | $ret .= "\r\n"; 417 | $ret .= "<LEDGERBAL>"; 418 | $ret .= "<BALAMT>" . (string)$ledge_balamt . "</BALAMT>"; 419 | $ret .= "<DTASOF>" . ENV_STR_DATE_TODAY . ENV_STR_OFX_TZ . "</DTASOF>"; 420 | $ret .= "</LEDGERBAL>"; 421 | $ret .= "\r\n"; 422 | 423 | // カード名称を出力する 424 | if($account["acctname"] != "") { 425 | $ret .= "<MKTGINFO>" . $account["acctname"] . "</MKTGINFO>"; 426 | $ret .= "\r\n"; 427 | } 428 | 429 | return $ret; 430 | } 431 | 432 | ?> 433 | -------------------------------------------------------------------------------- /server/smcprepaide.inc: -------------------------------------------------------------------------------- 1 | <?php 2 | /* 3 | smcprepaide.inc: 三井住友VISAプリペイドeのHTMLよりOFXファイルを生成する 4 | Copyright (C) 2014-2017 OFFICE OUTERGUY. All rights reserved. 5 | mailto:contact@beatrek.com 6 | Licensed under the GNU AGPLv3. 7 | */ 8 | 9 | // ログイン情報を取得する 10 | $user = $ofxforms["loginId"]; 11 | $pass = $ofxforms["loginPassword"]; 12 | $auth = urlencode(mb_convert_encoding(urldecode($ofxforms["authCode"]), "Shift_JIS", "UTF-8")); 13 | $sesscookie = $ofxforms["sesscookie"]; 14 | $accesskey = $ofxforms["accesskey"]; 15 | 16 | $resp = array(); 17 | $ofx = ""; 18 | 19 | if($sesscookie != "") list($cookie, $dummy) = explode("\t", sess_decode($sesscookie)); 20 | if($accesskey != "") { 21 | list($ssid, $method, $uri, $query, $svid, $dummy) = explode("\t", sess_decode($accesskey), 6); 22 | $sid = (integer)$ssid; 23 | } 24 | 25 | // 実行時間(タイムアウト)を再設定する 26 | @set_time_limit(ENV_NUM_TIMEOUT); 27 | 28 | if($sid == 0) { 29 | // ホーム画面を取得する 30 | $method = "GET"; 31 | $uris = parse_uri($settings["home"]); 32 | $query = ""; 33 | $cookie = ""; 34 | list($head, $body) = smcprepaide_http11($method, $uris, $query, $cookie); 35 | 36 | // リダイレクトする 37 | $retry = 0; 38 | while($retry++ < ENV_NUM_HTTP11_RETRY) { 39 | $locations = parse_header($head, "location"); 40 | if(count($locations) > 0) { 41 | $method = "GET"; 42 | $uris = parse_uri($locations[0], $uris); 43 | $query = ""; 44 | $cookie = smcprepaide_update_cookie($head, $cookie); 45 | list($head, $body) = smcprepaide_http11($method, $uris, $query, $cookie); 46 | } 47 | } 48 | 49 | // ログイン画面を取得する 50 | $as = parse_tag($body, "a"); 51 | foreach($as as $a) if(parse_tag_search(parse_tag($a["innerHTML"], "img"), "alt", "ログイン") != -1) { 52 | $method = "GET"; 53 | $uris = parse_uri($a["href"], $uris); 54 | $query = ""; 55 | $cookie = smcprepaide_update_cookie($head, $cookie); 56 | list($head, $body) = smcprepaide_http11($method, $uris, $query, $cookie); 57 | break; 58 | } 59 | 60 | // リダイレクトする 61 | $scripts = parse_tag($body, "script"); 62 | foreach($scripts as $script) if(preg_match("/window\.location[\s\t]*=[\s\t]*\"(.*?)\";/i", $script["innerHTML"], $matches) > 0) { 63 | $method = "GET"; 64 | $uris = parse_uri($matches[1], $uris); 65 | $query = ""; 66 | $cookie = smcprepaide_update_cookie($head, $cookie); 67 | list($head, $body) = smcprepaide_http11($method, $uris, $query, $cookie); 68 | break; 69 | } 70 | 71 | // svidを取得する 72 | $svid = ""; 73 | $scripts = parse_tag($body, "script"); 74 | foreach($scripts as $script) if(preg_match("/svid[\s\t]*=[\s\t]*\"(.*?)\";/i", $script["innerHTML"], $matches) > 0) { 75 | $svid = $matches[1]; 76 | break; 77 | } 78 | 79 | // 画像認証の画像を取得する 80 | $imgs = parse_tag($body, "img"); 81 | $c = parse_tag_search($imgs, "id", "captchaImage"); 82 | if($c != -1) { 83 | $imguris = parse_uri($imgs[$c]["src"], $uris); 84 | list($imghead, $imgbody) = smcprepaide_http11($method, $imguris, $query, $cookie, $uris["scheme"] . "://" . $uris["host"] . $uris["path"] . $query); 85 | $imgsrc = "data:image/jpeg;base64," . base64_encode($imgbody); 86 | $cookie = smcprepaide_update_cookie($imghead, $cookie); 87 | } 88 | 89 | // ログインする 90 | $forms = parse_tag($body, "form"); 91 | $c = parse_tag_search($forms, "id", "WB0102SC01Form"); 92 | if($c != -1) { 93 | $inputs = parse_tag($forms[$c]["innerHTML"], "input"); 94 | $queries = array(); 95 | foreach($inputs as $input) if($input["name"] != "") $queries[$input["name"]] = urlencode($input["name"]) . "=" . urlencode($input["value"]); 96 | $queries["loginId"] = "loginId=" . $user; 97 | $queries["loginPassword"] = "loginPassword=" . $pass; 98 | $queries["authCode"] = "authCode="; 99 | // if(isset($queries["forward_login"]) == true) unset($queries["forward_login"]); 100 | 101 | $method = $forms[$c]["method"]; 102 | $uris = parse_uri($forms[$c]["action"], $uris); 103 | $query = implode("&", $queries); 104 | } 105 | 106 | // セッションを退避する 107 | $sid = 1; 108 | $head = ""; 109 | $body = ""; 110 | } else if($sid == 1) { 111 | // セッションを復元する 112 | $sid = 0; 113 | $uris = parse_uri($uri); 114 | $query = str_replace("authCode=", "authCode=" . $auth, $query); 115 | list($head, $body) = smcprepaide_http11($method, $uris, $query, $cookie); 116 | } 117 | 118 | if($sid > 0) { 119 | // セッションを引き継ぐ 120 | $resp["status"] = ENV_NUM_STATUS_ADDITION; 121 | $resp["aid"] = "authCode"; 122 | $resp["additional"] = $imgsrc; 123 | $resp["sid"] = $sid; 124 | $resp["sesscookie"] = sess_encode(implode("\t", array($cookie, ENV_STR_SESSION_PADDING))); 125 | $resp["accesskey"] = sess_encode(implode("\t", array((string)$sid, $method, $uris["scheme"] . "://" . $uris["host"] . $uris["path"], $query, $svid, ENV_STR_SESSION_PADDING))); 126 | 127 | $mfachallengetrnrs = ""; 128 | $mfachallengetrnrs .= "<MFACHALLENGETRNRS>"; 129 | $mfachallengetrnrs .= "<MFACHALLENGERS>"; 130 | $mfachallengetrnrs .= "<MFACHALLENGE>"; 131 | $mfachallengetrnrs .= "<MFAPHRASEID>" . $resp["aid"] . "</MFAPHRASEID>"; 132 | $mfachallengetrnrs .= "<MFAPHRASELABEL>" . $resp["additional"] . "</MFAPHRASELABEL>"; 133 | $mfachallengetrnrs .= "</MFACHALLENGE>"; 134 | $mfachallengetrnrs .= "</MFACHALLENGERS>"; 135 | $mfachallengetrnrs .= "</MFACHALLENGETRNRS>"; 136 | 137 | $resp["ofx"] = generate_ofx($resp["status"], $mfachallengetrnrs, $resp["sesscookie"], $resp["accesskey"]); 138 | } else if(strpos($body, "定例または臨時メンテナンスのため") !== false) { 139 | // システムメンテナンス画面の場合 140 | $resp["status"] = ENV_NUM_STATUS_MAINTENANCE; 141 | $resp["method"] = $method; 142 | $resp["uri"] = $uris["scheme"] . "://" . $uris["host"] . $uris["path"]; 143 | $resp["query"] = $query; 144 | $resp["cookie"] = $cookie; 145 | $resp["head"] = $head; 146 | $resp["body"] = $body; 147 | $resp["ofx"] = generate_ofx($resp["status"]); 148 | } else if(strpos($body, "重要なお知らせがあります") !== false) { 149 | // ログイン後の画面が通常と異なる場合 150 | $resp["status"] = ENV_NUM_STATUS_CAUTION; 151 | $resp["method"] = $method; 152 | $resp["uri"] = $uris["scheme"] . "://" . $uris["host"] . $uris["path"]; 153 | $resp["query"] = $query; 154 | $resp["cookie"] = $cookie; 155 | $resp["head"] = $head; 156 | $resp["body"] = $body; 157 | $resp["ofx"] = generate_ofx($resp["status"]); 158 | } else if(strpos($body, "前回ログイン") === false) { 159 | // ログイン失敗の場合 160 | $resp["status"] = ENV_NUM_STATUS_FAILURE; 161 | $resp["method"] = $method; 162 | $resp["uri"] = $uris["scheme"] . "://" . $uris["host"] . $uris["path"]; 163 | $resp["query"] = $query; 164 | $resp["cookie"] = $cookie; 165 | $resp["head"] = $head; 166 | $resp["body"] = $body; 167 | $resp["ofx"] = generate_ofx($resp["status"]); 168 | } else { 169 | $accounts = array(); 170 | 171 | // 口座数分ループする 172 | $forms = parse_tag($body, "form"); 173 | for($c = 1; $c < count($forms); $c++) { 174 | // 登録カード詳細画面を取得する 175 | $inputs = parse_tag($forms[$c]["innerHTML"], "input"); 176 | $queries = array(); 177 | foreach($inputs as $input) if($input["name"] != "") $queries[$input["name"]] = urlencode($input["name"]) . "=" . urlencode($input["value"]); 178 | // if(isset($queries["forward_toWB3202SC01"]) == true) unset($queries["forward_toWB3202SC01"]); // 詳細 179 | if(isset($queries["forward_toWB2301SC01"]) == true) unset($queries["forward_toWB2301SC01"]); // チャージ 180 | if(isset($queries["forward_toWB2601SC01"]) == true) unset($queries["forward_toWB2601SC01"]); // ロック 181 | if(isset($queries["forward_toWB2602SC01"]) == true) unset($queries["forward_toWB2602SC01"]); // ロック解除 182 | if(isset($queries["forward_toWB3301SC01"]) == true) unset($queries["forward_toWB3301SC01"]); // 利用履歴照会 183 | if(isset($queries["forward_toWB2901SC01"]) == true) unset($queries["forward_toWB2901SC01"]); // 暗証番号設定 184 | 185 | $method = $forms[$c]["method"]; 186 | $uris = parse_uri($forms[$c]["action"], $uris); 187 | $query = implode("&", $queries); 188 | $cookie = smcprepaide_update_cookie($head, $cookie); 189 | list($head, $body) = smcprepaide_http11($method, $uris, $query, $cookie); 190 | 191 | // 利用履歴照会画面を取得する 192 | $forms2 = parse_tag($body, "form"); 193 | $inputs = parse_tag($forms2[0]["innerHTML"], "input"); 194 | 195 | // 口座名(ニックネーム)を取得する 196 | $d = parse_tag_search($inputs, "name", "cardNickname"); 197 | if($d != -1) $accounts[$c - 1]["acctname"] = $settings["name"] . ENV_CHR_CONCATENATOR . $inputs[$d]["value"]; 198 | 199 | // 支店番号を取得する 200 | $accounts[$c - 1]["branchid"] = "0"; 201 | 202 | // 口座番号を取得する 203 | $d = parse_tag_search($inputs, "name", "vcn"); 204 | if($d != -1) $accounts[$c - 1]["acctid"] = $inputs[$d]["value"]; 205 | 206 | // 残高を取得する 207 | $d = parse_tag_search($inputs, "name", "chargeBalance"); 208 | if($d != -1) $accounts[$c - 1]["balance"] = $inputs[$d]["value"]; 209 | 210 | $queries = array(); 211 | foreach($inputs as $input) if($input["name"] != "") $queries[$input["name"]] = urlencode($input["name"]) . "=" . urlencode($input["value"]); 212 | unset($queries["forward_toWB2301SC01"]); // チャージ 213 | // if(isset($queries["forward_toWB3301SC01"]) == true) unset($queries["forward_toWB3301SC01"]); // 利用履歴照会 214 | if(isset($queries["forward_toWB2601SC01"]) == true) unset($queries["forward_toWB2601SC01"]); // ご利用ロック設定・解除 215 | if(isset($queries["forward_toWB2701SC01"]) == true) unset($queries["forward_toWB2701SC01"]); // カード名称の変更 216 | if(isset($queries["forward_toWB2901SC01"]) == true) unset($queries["forward_toWB2901SC01"]); // 暗証番号設定 217 | if(isset($queries["forward_toWB3201SC01"]) == true) unset($queries["forward_toWB3201SC01"]); // 戻る 218 | 219 | $method = $forms2[0]["method"]; 220 | $uris = parse_uri($forms2[0]["action"], $uris); 221 | $query = implode("&", $queries); 222 | $cookie = smcprepaide_update_cookie($head, $cookie); 223 | list($head, $body) = smcprepaide_http11($method, $uris, $query, $cookie); 224 | 225 | $detail = ""; 226 | 227 | do { 228 | $tbodys = parse_tag($body, "tbody"); 229 | if(count($tbodys) > 1) $detail .= $tbodys[1]["innerHTML"]; 230 | 231 | $as = parse_tag($body, "a"); 232 | $d = parse_tag_search($as, "innerHTML", "次へ"); 233 | if($d != -1) { 234 | $metod = "GET"; 235 | $uris = parse_uri($as[$d]["href"], $uris); 236 | $query = ""; 237 | $cookie = smcprepaide_update_cookie($head, $cookie); 238 | list($head, $body) = smcprepaide_http11($method, $uris, $query, $cookie); 239 | } 240 | } while($d != -1); 241 | 242 | if($detail != "") $accounts[$c - 1]["details"] = smcprepaide_get_details($detail); 243 | 244 | /* 245 | // カード一覧画面を取得する 246 | $as = parse_tag($body, "a"); 247 | $c = parse_tag_search($as, "innerHTML", "カード一覧"); 248 | if($c != -1) { 249 | $method = "GET"; 250 | $uris = parse_uri($as[$c]["href"] . $svid, $uris); 251 | $query = ""; 252 | $cookie = smcprepaide_update_cookie($head, $cookie); 253 | list($head, $body) = smcprepaide_http11($method, $uris, $query, $cookie); 254 | } 255 | */ 256 | } 257 | 258 | // 実行時間(タイムアウト)を再設定する 259 | @set_time_limit(ENV_NUM_TIMEOUT); 260 | 261 | // ログアウトする 262 | $as = parse_tag($body, "a"); 263 | foreach($as as $a) if(parse_tag_search(parse_tag($a["innerHTML"], "img"), "alt", "ログアウト") != -1) { 264 | $method = "GET"; 265 | $uris = parse_uri($a["href"] . $svid, $uris); 266 | $query = ""; 267 | $cookie = smcprepaide_update_cookie($head, $cookie); 268 | list($head, $body) = smcprepaide_http11($method, $uris, $query, $cookie); 269 | break; 270 | } 271 | 272 | $bankmsgsrsv1 = ""; 273 | $bankmsgsrsv1 .= "<BANKMSGSRSV1>"; 274 | $bankmsgsrsv1 .= "\r\n"; 275 | 276 | foreach($accounts as $account) { 277 | // 口座情報を取得する 278 | $bankmsgsrsv1 .= "<STMTTRNRS>"; 279 | $bankmsgsrsv1 .= "\r\n"; 280 | $bankmsgsrsv1 .= "<TRNUID>0</TRNUID>"; 281 | $bankmsgsrsv1 .= "\r\n"; 282 | $bankmsgsrsv1 .= "<STATUS><CODE>0</CODE><SEVERITY>INFO</SEVERITY></STATUS>"; 283 | $bankmsgsrsv1 .= "\r\n"; 284 | $bankmsgsrsv1 .= "<STMTRS>"; 285 | $bankmsgsrsv1 .= "\r\n"; 286 | $bankmsgsrsv1 .= "<CURDEF>" . ENV_STR_OFX_CURRENCY_JPY . "</CURDEF>"; 287 | $bankmsgsrsv1 .= "\r\n"; 288 | $bankmsgsrsv1 .= "<BANKACCTFROM>"; 289 | $bankmsgsrsv1 .= "<BANKID>" . $settings["code"] . "</BANKID>"; 290 | $bankmsgsrsv1 .= "<BRANCHID>" . $account["branchid"] . "</BRANCHID>"; 291 | $bankmsgsrsv1 .= "<ACCTID>" . $account["acctid"] . "</ACCTID>"; 292 | $bankmsgsrsv1 .= "<ACCTTYPE>" . ENV_STR_ACCTTYPE_SAVINGS . "</ACCTTYPE>"; 293 | $bankmsgsrsv1 .= "</BANKACCTFROM>"; 294 | $bankmsgsrsv1 .= "\r\n"; 295 | $bankmsgsrsv1 .= smcprepaide_parse_details($account); 296 | $bankmsgsrsv1 .= "</STMTRS>"; 297 | $bankmsgsrsv1 .= "\r\n"; 298 | $bankmsgsrsv1 .= "</STMTTRNRS>"; 299 | $bankmsgsrsv1 .= "\r\n"; 300 | } 301 | 302 | $bankmsgsrsv1 .= "</BANKMSGSRSV1>"; 303 | $bankmsgsrsv1 .= "\r\n"; 304 | 305 | // OFXファイルを出力する 306 | $resp["status"] = ENV_NUM_STATUS_SUCCESS; 307 | if(strpos($bankmsgsrsv1, "<BANKTRANLIST>") === false) { 308 | // 明細が存在しない場合 309 | $resp["ofx"] = generate_ofx($resp["status"]); 310 | } else { 311 | // 明細が存在する場合 312 | $resp["ofx"] = generate_ofx($resp["status"], $bankmsgsrsv1); 313 | } 314 | } 315 | return $resp; 316 | 317 | // HTTP/1.1 318 | function smcprepaide_http11($method, $uris, $query = "", $cookie = "", $referer = "") { 319 | $ret = "INVALID HOST"; 320 | if(preg_match("/\.smbc-card\.com$/", $uris["host"]) > 0 || preg_match("/\.vpass\.ne\.jp$/", $uris["host"]) > 0) $ret = http11(strtoupper($method), $uris["scheme"], $uris["host"], 0, $uris["path"], $query, "", $cookie, true, ENV_PRODUCT_UA, "", $referer); 321 | return explode("\r\n\r\n", $ret, 2); 322 | } 323 | 324 | function smcprepaide_update_cookie($head, $cookie) { 325 | return update_cookie(array("JSESSIONID"), parse_header($head, "set-cookie"), $cookie); 326 | } 327 | 328 | function smcprepaide_get_details($body) { 329 | $rets = array(); 330 | $i = 0; 331 | $trs = array_reverse(parse_tag($body, "tr")); 332 | foreach($trs as $tr) { 333 | $tds = parse_tag($tr["innerHTML"], "td"); 334 | if(count($tds) == 9) { 335 | // ご利用日時を取得する 336 | $dt = explode(" ", trim(strip_tags($tds[2]["innerHTML"]))); 337 | 338 | // 期限外の明細を除外する 339 | if(ENV_STR_DATE_PASTDAY > parse_date($dt[0])) continue; 340 | 341 | $rets[$i]["date"] = parse_date($dt[0]); 342 | 343 | // 支払区分、ご利用店名、ご入金額、およびご利用金額を取得する 344 | $buf = trim(strip_tags($tds[3]["innerHTML"])); 345 | switch($buf) { 346 | case "仮発行番号入力": 347 | case "返金": 348 | case "チャージ": // debug 349 | $name = $buf; 350 | $memo = trim(strip_tags($tds[8]["innerHTML"])); 351 | $amount = parse_amount(trim(strip_tags($tds[5]["innerHTML"]))); 352 | break; 353 | case "利用": 354 | default: 355 | $name = trim(strip_tags($tds[4]["innerHTML"])); 356 | $memo = trim(strip_tags($tds[1]["innerHTML"])); 357 | $memo2 = trim(strip_tags($tds[8]["innerHTML"])); 358 | if($name == "") $name = $buf; 359 | if($memo2 != "") $memo .= ENV_CHR_CONCATENATOR . $memo2; 360 | $amount = "-" . parse_amount(trim(strip_tags($tds[6]["innerHTML"]))); 361 | break; 362 | } 363 | $rets[$i]["summary"] = $name; 364 | $rets[$i]["memo"] = ($memo != ""? $memo: ENV_STR_OFX_MEMO); 365 | 366 | // ご利用金額を取得する 367 | $rets[$i]["amount"] = $amount; 368 | 369 | $i++; 370 | } 371 | } 372 | 373 | return $rets; 374 | } 375 | 376 | function smcprepaide_parse_details($account) { 377 | $ret = ""; 378 | $cds = array(); 379 | $cd_date = ""; 380 | $cd_num = 0; 381 | foreach($account["details"] as $line) { 382 | $cd = array(); 383 | $cd["TRNTYPE"] = ENV_STR_OFX_TRNTYPE_DIRECTDEBIT; 384 | 385 | // 日付を取得する 386 | $cd["DTPOSTED"] = $line["date"]; 387 | 388 | // 通番を生成する 389 | if($cd["DTPOSTED"] == $cd_date) $cd_num++; else $cd_num = 0; 390 | 391 | // トランザクション番号を生成する 392 | $cd["FITID"] = $cd["DTPOSTED"] . "0000000" . sprintf("%05d", $cd_num); 393 | 394 | // 摘要を取得する 395 | $cd["NAME"] = $line["summary"]; 396 | 397 | // 金額を取得する 398 | $cd["TRNAMT"] = parse_amount($line["amount"]); 399 | $cd["MEMO"] = ($line["memo"] != ""? $line["memo"]: ENV_STR_OFX_MEMO); 400 | 401 | array_push($cds, $cd); 402 | $cd_date = $cd["DTPOSTED"]; 403 | } 404 | // BANKTRANLIST 405 | $ret .= "<BANKTRANLIST>"; 406 | $ret .= "\r\n"; 407 | $ret .= "<DTSTART>" . ENV_STR_DATE_PASTDAY . ENV_STR_OFX_TZ . "</DTSTART>"; 408 | $ret .= "<DTEND>" . ENV_STR_DATE_TODAY . ENV_STR_OFX_TZ . "</DTEND>"; 409 | $ret .= "\r\n"; 410 | 411 | foreach($cds as $cd) { 412 | $ret .= "<STMTTRN>"; 413 | $ret .= "<TRNTYPE>" . $cd["TRNTYPE"] . "</TRNTYPE>"; 414 | $ret .= "<DTPOSTED>" . $cd["DTPOSTED"] . ENV_STR_OFX_TZ . "</DTPOSTED>"; 415 | $ret .= "<TRNAMT>" . $cd["TRNAMT"] . "</TRNAMT>"; 416 | $ret .= "<FITID>" . $cd["FITID"] . "</FITID>"; 417 | $ret .= "<NAME>" . $cd["NAME"] . "</NAME>"; 418 | $ret .= "<MEMO>" . $cd["MEMO"] . "</MEMO>"; 419 | $ret .= "</STMTTRN>"; 420 | $ret .= "\r\n"; 421 | } 422 | 423 | $ret .= "</BANKTRANLIST>"; 424 | $ret .= "\r\n"; 425 | $ret .= "<LEDGERBAL>"; 426 | $ret .= "<BALAMT>" . $account["balance"] . "</BALAMT>"; 427 | $ret .= "<DTASOF>" . ENV_STR_DATE_TODAY . ENV_STR_OFX_TZ . "</DTASOF>"; 428 | $ret .= "</LEDGERBAL>"; 429 | $ret .= "\r\n"; 430 | 431 | // 口座名称を出力する 432 | if($account["acctname"] != "") { 433 | $ret .= "<MKTGINFO>" . $account["acctname"] . "</MKTGINFO>"; 434 | $ret .= "\r\n"; 435 | } 436 | 437 | return $ret; 438 | } 439 | 440 | ?> 441 | -------------------------------------------------------------------------------- /server/surugavisacard.inc: -------------------------------------------------------------------------------- 1 | <?php 2 | /* 3 | surugavisacard.inc: スルガ銀行 VISAデビット/VISAクレジットのHTMLよりOFXファイルを生成する 4 | Copyright (C) 2012-2017 Hiromu2000. All Rights Reserved. 5 | mailto:hiromu2000@hotmail.com 6 | Licensed under the GNU AGPLv3. 7 | */ 8 | 9 | // ログイン情報を取得する 10 | $user = $ofxforms["loginID"]; 11 | $pass1 = $ofxforms["telPin"]; 12 | $pass2 = $ofxforms["webPin"]; 13 | $mode = $ofxforms["mode"]; 14 | 15 | $resp = array(); 16 | $resp["status"] = ENV_NUM_STATUS_NONE; 17 | $ofx = ""; 18 | 19 | // 実行時間(タイムアウト)を再設定する 20 | @set_time_limit(ENV_NUM_TIMEOUT); 21 | 22 | // ホーム画面を取得する 23 | $urls = parse_url($settings["home"]); 24 | $method = "GET"; 25 | $protocol = ($urls["scheme"] != ""? $urls["scheme"]: ""); 26 | $host = ($urls["host"] != ""? $urls["host"]: ""); 27 | $page = ($urls["path"] != ""? $urls["path"]: "/"); 28 | $query = ""; 29 | $cookie = ""; 30 | list($head, $body) = surugavisa_http11($method, $protocol, $host, $page, $query, $cookie); 31 | 32 | // ログイン画面を取得する 33 | $protocol = 'https'; 34 | $page = '/Top.do'; 35 | $cookie = surugavisa_updatecookie($head, $cookie); 36 | list($head, $body) = surugavisa_http11($method, $protocol, $host, $page, $query, $cookie); 37 | 38 | // ログインする 39 | $forms = parse_tag($body, "form"); 40 | $c = parse_tag_search($forms, "name", "loginForm"); 41 | $method = "POST"; 42 | $urls = parse_url($forms[$c]['action']); 43 | if($urls["scheme"] != "") $protocol = $urls["scheme"]; 44 | if($urls["host"] != "") $host = $urls["host"]; 45 | if($urls["path"] != "") $page = $urls["path"]; 46 | if($urls["query"] != "") $page .= "?" . $urls["query"]; 47 | 48 | $inputs = parse_tag($forms[$c]["innerHTML"], "input"); 49 | $queries = array(); 50 | foreach ($inputs as $input) { 51 | if ($input["name"] != "") { 52 | $queries[$input["name"]] = urlencode($input["name"]) . "=" . urlencode($input["value"]); 53 | } 54 | } 55 | $queries["loginID"] .= $user; 56 | $queries["telPin"] .= $pass1; 57 | $queries["webPin"] .= $pass2; 58 | $query = implode("&", $queries); 59 | $cookie = surugavisa_updatecookie($head, $cookie); 60 | list($head, $body) = surugavisa_http11($method, $protocol, $host, $page, $query, $cookie); 61 | 62 | if(strpos($body, "只今メンテナンス中です") !== false) { 63 | // システムメンテナンス画面の場合 64 | $resp["status"] = ENV_NUM_STATUS_MAINTENANCE; 65 | $resp["method"] = $method; 66 | $resp["uri"] = $uris["scheme"] . "://" . $uris["host"] . $uris["path"]; 67 | $resp["query"] = $query; 68 | $resp["cookie"] = $cookie; 69 | $resp["head"] = $head; 70 | $resp["body"] = $body; 71 | $resp["ofx"] = generate_ofx($resp["status"]); 72 | } else if(strpos($body, "loginForm") !== false) { 73 | // ログイン失敗の場合 74 | $resp["status"] = ENV_NUM_STATUS_FAILURE; 75 | $resp["method"] = $method; 76 | $resp["uri"] = $uris["scheme"] . "://" . $uris["host"] . $uris["path"]; 77 | $resp["query"] = $query; 78 | $resp["cookie"] = $cookie; 79 | $resp["head"] = $head; 80 | $resp["body"] = $body; 81 | $resp["ofx"] = generate_ofx($resp["status"]); 82 | } else { 83 | // カード名称・カード番号を取得する 84 | $account['acctname'] = 'スルガ Visaデビット/クレジット'; 85 | $account['acctid'] = substr($user, 12); 86 | // DOMツリーを生成 87 | $ofxdom = new ofxDOM("CREDITCARD", $settings["name"]); 88 | $ofxdom->setAcctfrom(array("ACCTID" => $account["acctid"])); 89 | 90 | // メニューから「ご利用明細」を選択 91 | $cds = array(); 92 | for ($i=0;$i<6;$i++) { 93 | $forms = parse_tag($body, "form"); 94 | $c = parse_tag_search($forms, "name", "meisaiForm"); 95 | $page = '/meisai.do'; 96 | $inputs = parse_tag($forms[$c]["innerHTML"], "input"); 97 | $queries = array(); 98 | foreach ($inputs as $input) { 99 | if ($input["name"] != "") { 100 | $queries[$input["name"]] = urlencode($input["name"]) . "=" . urlencode($input["value"]); 101 | } 102 | } 103 | $queries["month"] = "month=" . $i; 104 | $query = implode("&", $queries); 105 | $cookie = surugavisa_updatecookie($head, $cookie); 106 | list($head, $body) = surugavisa_http11($method, $protocol, $host, $page, $query, $cookie); 107 | // 明細をパース 108 | $cds = array_merge($cds, surugavisa_parsedom($body)); 109 | } 110 | usort($cds, function($a, $b) { 111 | return $a['DTPOSTED'] > $b['DTPOSTED']; 112 | }); 113 | foreach($cds as $cd) { 114 | $ofxdom->addTran($cd); 115 | } 116 | $cds_balamt = 0; 117 | $cds_s = ""; 118 | $cds_e = ""; 119 | $items = $ofxdom->getTrans(); 120 | foreach ($items as $item) { 121 | $dtposted = $item->DTPOSTED; 122 | // DTSTART, DTENDを取得 123 | if($cds_s == "") $cds_s = $dtposted; 124 | $cds_e = $dtposted; 125 | // 残高を計算 126 | $cds_balamt += (double)$item->TRNAMT; 127 | } 128 | 129 | // DTSTARTとDTENDを設定する 130 | $ofxdom->setDateRange($cds_s, $cds_e); 131 | 132 | // 残高を処理 133 | $cds_balamt = (-1)*$cds_balamt; 134 | $ofxdom->setBalance(array( 135 | 'BALAMT' => $cds_balamt, 136 | 'DTASOF' => ENV_STR_DATE_TODAY . ENV_STR_OFX_TZ 137 | )); 138 | 139 | // FITIDを仕上げる 140 | $ofxdom->setFitid(); 141 | // XML DOMツリーを文字列に変換 142 | $xml = $ofxdom->getXML(); 143 | 144 | $resp["status"] = ENV_NUM_STATUS_SUCCESS; 145 | $resp["ofx"] = generate_ofx($mode, $xml); 146 | 147 | // 実行時間(タイムアウト)を再設定する 148 | @set_time_limit(ENV_NUM_TIMEOUT); 149 | 150 | // ログアウトする 151 | $forms = parse_tag($body, "form"); 152 | $c = parse_tag_search($forms, "name", "logoutForm"); 153 | $page = '/logout.do'; 154 | $inputs = parse_tag($forms[$c]["innerHTML"], "input"); 155 | $queries = array(); 156 | foreach ($inputs as $input) { 157 | if ($input["name"] != "") { 158 | $queries[$input["name"]] = urlencode($input["name"]) . "=" . urlencode($input["value"]); 159 | } 160 | } 161 | $query = implode("&", $queries); 162 | $cookie = surugavisa_updatecookie($head, $cookie); 163 | list($head, $body) = surugavisa_http11($method, $protocol, $host, $page, $query, $cookie); 164 | } 165 | return $resp; 166 | 167 | // HTTP/1.1 168 | function surugavisa_http11($method, $protocol, $host, $page = "/", $query = "", $cookie = "") { 169 | $ret = "INVALID HOST"; 170 | if(preg_match("/card\.surugabank\.co\.jp$/", $host) > 0) $ret = http11($method, $protocol, $host, 0, $page, $query, "", $cookie); 171 | if(preg_match("/[Ll][Oo][Cc][Aa][Tt][Ii][Oo][Nn][\s\t]*:[\s\t]*([^\r\n]+)/", $ret, $matches) > 0) { 172 | $urls = parse_url($matches[1]); 173 | if($urls["scheme"] != "") $protocol = $urls["scheme"]; 174 | if($urls["host"] != "") $host = $urls["host"]; 175 | if($urls["path"] != "") $page = $urls["path"]; 176 | $query = ($urls["query"] != ""? $urls["query"]: ""); 177 | return surugavisa_http11($method, $protocol, $host, $page, $query, $cookie); 178 | } 179 | return explode("\r\n\r\n", $ret, 2); 180 | } 181 | 182 | function surugavisa_updatecookie($head, $cookie) { 183 | return update_cookie(array("JSESSIONID"), parse_header($head, "set-cookie"), $cookie); 184 | } 185 | 186 | function surugavisa_parsedom($str) { 187 | // 明細表読み込み用DOMツリー作成 188 | $doc = new DOMDocument(); 189 | // <meta … charset=Shift_JIS">の前の<title>が,文字化けの原因となるため,削除 190 | preg_match("/(<body.*<\/body>)/s", $str, $matches); 191 | $str = $matches[1]; 192 | // ヘッダ付加 193 | $str = "<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\"><\/head>" . $str . "<\/html>"; 194 | // 文字エンコード変換 195 | // $str = mb_convert_encoding($str, 'UTF-8', 'SJIS'); 196 | //   197 | $str = str_replace(" ", "", $str); 198 | // HTMLからDOMツリー作成 199 | @$doc->loadHTML($str); 200 | $xpath = new DOMXPath($doc); 201 | // 明細表のテーブルを指定 202 | $rows = $xpath->query("//table[@class='table-type2 clear margin-b-10px']/tr"); 203 | 204 | $ret = ""; 205 | $cds = array(); 206 | $nrow = $rows->length; 207 | 208 | for($i=0; $i<$nrow; $i++) { 209 | $cd = array(); 210 | $row = $rows->item($i); 211 | $cols1 = $row->getElementsByTagName('th'); 212 | $cols2 = $row->getElementsByTagName('td'); 213 | // 利用明細でない行はスキップ 214 | if ($cols1->length != 2) continue; 215 | 216 | $cd["TRNTYPE"] = ENV_STR_OFX_TRNTYPE_CREDIT; 217 | 218 | // 日付を取得する 219 | preg_match("/([0-9]{4}).*?([0-9]{1,2}).*?([0-9]{1,2})/", str_replace(" ", "", $cols1->item(1)->nodeValue), $matches); 220 | $cd["DTPOSTED"] = sprintf("%d%02d%02d", $matches[1], $matches[2], $matches[3]); 221 | $cd["DTPOSTED"] .= ENV_STR_OFX_TZ; 222 | 223 | // トランザクション番号(請求月とデータ種別)を生成する 224 | $cd["FITID"] = '000'; 225 | // 摘要を取得する 226 | $cd["NAME"] = $cols2->item(0)->nodeValue; 227 | // $cd["NAME"] = preg_replace('/-/', mb_convert_encoding('ー', 'UTF-8', 'sjis-win'), $cd["NAME"]); 228 | $cd["NAME"] = str_replace('-', 'ー', $cd["NAME"]); 229 | // 金額を取得する 230 | $cd["TRNAMT"] = (-1)*(double)parse_amount(trim($cols2->item(1)->nodeValue)); 231 | if (strpos($cols1->item(0)->nodeValue, "取消") !== false) { 232 | $cd["NAME"] .= "(取消)"; 233 | $cd["TRNAMT"] *= -1; 234 | } 235 | array_push($cds, $cd); 236 | } 237 | return $cds; 238 | 239 | } 240 | ?> 241 | -------------------------------------------------------------------------------- /server/viewcard.inc: -------------------------------------------------------------------------------- 1 | <?php 2 | /* 3 | viewcard.inc: ビューカードのCSVよりOFXファイルを生成する 4 | Copyright (C) 2012-2017 OFFICE OUTERGUY. All rights reserved. 5 | mailto:contact@beatrek.com 6 | Licensed under the GNU AGPLv3. 7 | */ 8 | 9 | // ログイン情報を取得する 10 | $user = $ofxforms["id"]; 11 | $pass = $ofxforms["pass"]; 12 | 13 | $resp = array(); 14 | $ofx = ""; 15 | 16 | // 実行時間(タイムアウト)を再設定する 17 | @set_time_limit(ENV_NUM_TIMEOUT); 18 | 19 | // ホーム画面を取得する 20 | $method = "GET"; 21 | $uris = parse_uri($settings["home"]); 22 | $query = ""; 23 | $cookie = ""; 24 | list($head, $body) = viewcard_http11($method, $uris, $query, $cookie); 25 | 26 | // ログイン画面を取得する 27 | $as = parse_tag($body, "a"); 28 | foreach($as as $a) if(strip_tags($a["innerHTML"]) == "VIEW's NETログイン(VIEW's NET IDの方)") { 29 | $method = "GET"; 30 | $uris = parse_uri($a["href"], $uris); 31 | $query = ""; 32 | $cookie = viewcard_update_cookie($head, $cookie); 33 | list($head, $body) = viewcard_http11($method, $uris, $query, $cookie); 34 | break; 35 | } 36 | 37 | // リダイレクトする 38 | $retry = 0; 39 | while($retry++ < ENV_NUM_HTTP11_RETRY) { 40 | $locations = parse_header($head, "location"); 41 | if(count($locations) > 0) { 42 | $method = "GET"; 43 | $uris = parse_uri($locations[0], $uris); 44 | $query = ""; 45 | $cookie = viewcard_update_cookie($head, $cookie); 46 | list($head, $body) = viewcard_http11($method, $uris, $query, $cookie); 47 | } 48 | } 49 | 50 | // ログインする 51 | $forms = parse_tag($body, "form"); 52 | $c = parse_tag_search($forms, "target", "_self"); 53 | if($c != -1) { 54 | $inputs = parse_tag($forms[$c]["innerHTML"], "input"); 55 | $queries = array(); 56 | foreach($inputs as $input) if($input["name"] != "") $queries[$input["name"]] = urlencode($input["name"]) . "=" . urlencode($input["value"]); 57 | $queries["id"] = "id=" . $user; 58 | $queries["pass"] = "pass=" . $pass; 59 | 60 | $method = $forms[$c]["method"]; 61 | $uris = parse_uri($forms[$c]["action"], $uris); 62 | $query = implode("&", $queries); 63 | $cookie = viewcard_update_cookie($head, $cookie); 64 | list($head, $body) = viewcard_http11($method, $uris, $query, $cookie); 65 | } 66 | 67 | // リダイレクトする 68 | $retry = 0; 69 | while($retry++ < ENV_NUM_HTTP11_RETRY) { 70 | $locations = parse_header($head, "location"); 71 | if(count($locations) > 0) { 72 | $method = "GET"; 73 | $uris = parse_uri($locations[0], $uris); 74 | $query = ""; 75 | $cookie = viewcard_update_cookie($head, $cookie); 76 | list($head, $body) = viewcard_http11($method, $uris, $query, $cookie); 77 | } 78 | } 79 | 80 | if(strpos($body, "前回ログイン") === false) { 81 | // ログイン失敗の場合 82 | $resp["status"] = ENV_NUM_STATUS_FAILURE; 83 | $resp["method"] = $method; 84 | $resp["uri"] = $uris["scheme"] . "://" . $uris["host"] . $uris["path"]; 85 | $resp["query"] = $query; 86 | $resp["cookie"] = $cookie; 87 | $resp["head"] = $head; 88 | $resp["body"] = $body; 89 | $resp["ofx"] = generate_ofx($resp["status"]); 90 | } else { 91 | // ご利用明細照会(お支払方法の変更)画面を取得する 92 | $as = parse_tag($body, "a"); 93 | $c = parse_tag_search($as, "alt", "ご利用明細照会(お支払方法の変更)"); 94 | if($c != -1) { 95 | $method = "GET"; 96 | $uris = parse_uri($as[$c]["href"], $uris); 97 | $query = ""; 98 | $cookie = viewcard_update_cookie($head, $cookie); 99 | list($head, $body) = viewcard_http11($method, $uris, $query, $cookie); 100 | } 101 | 102 | // リダイレクトする 103 | $retry = 0; 104 | while($retry++ < ENV_NUM_HTTP11_RETRY) { 105 | $locations = parse_header($head, "location"); 106 | if(count($locations) > 0) { 107 | $method = "GET"; 108 | $uris = parse_uri($locations[0], $uris); 109 | $query = ""; 110 | $cookie = viewcard_update_cookie($head, $cookie); 111 | list($head, $body) = viewcard_http11($method, $uris, $query, $cookie); 112 | } 113 | } 114 | 115 | $accounts = array(); 116 | 117 | // カード数を取得する 118 | $selects = parse_tag($body, "select"); 119 | $c = parse_tag_search($selects, "name", "DdlCardNO"); 120 | if($c != -1) { 121 | $options = parse_tag($selects[$c]["innerHTML"], "option"); 122 | for($i = 0; $i < count($options); $i++) { 123 | $accounts[$i]["id"] = $options[$i]["value"]; 124 | $accounts[$i]["ym"] = $ym; 125 | if(preg_match("/(.*?)[\s\t]*([0-9\*\-]+)/", trim(strip_tags($options[$i]["innerHTML"])), $matches) > 0) { 126 | // カード名称を取得する 127 | $accounts[$i]["acctname"] = implode(ENV_CHR_CONCATENATOR, array($settings["name"], $matches[1])); 128 | 129 | $accounts[$i]["name"] = $settings["name"]; 130 | 131 | // カード番号を取得する 132 | $accounts[$i]["acctid"] = $matches[2]; 133 | } 134 | } 135 | } 136 | 137 | $body_old = $body; 138 | 139 | $creditcardmsgsrsv1 = ""; 140 | $creditcardmsgsrsv1 .= "<CREDITCARDMSGSRSV1>"; 141 | $creditcardmsgsrsv1 .= "\r\n"; 142 | 143 | // カード数分ループする 144 | foreach($accounts as $account) { 145 | $body = $body_old; 146 | 147 | // 実行時間(タイムアウト)を再設定する 148 | @set_time_limit(ENV_NUM_TIMEOUT); 149 | 150 | // 確定済みの最新明細画面を取得する 151 | $forms = parse_tag($body, "form"); 152 | $c = parse_tag_search($forms, "name", "Frm002"); 153 | if($c != -1) { 154 | $inputs = parse_tag($forms[$c]["innerHTML"], "input"); 155 | $queries = array(); 156 | foreach($inputs as $input) if($input["name"] != "") $queries[$input["name"]] = urlencode($input["name"]) . "=" . urlencode($input["value"]); 157 | $queries["DdlCardNO"] = "DdlCardNO=" . $account["id"]; 158 | $queries["__EVENTTARGET"] = "__EVENTTARGET=LnkClaimYm1"; // 確定済みの最新明細 159 | 160 | $method = $forms[$c]["method"]; 161 | $uris = parse_uri($forms[$c]["action"], $uris); 162 | $query = implode("&", $queries); 163 | $cookie = viewcard_update_cookie($head, $cookie); 164 | list($head, $body) = viewcard_http11($method, $uris, $query, $cookie); 165 | } 166 | 167 | // リダイレクトする 168 | $retry = 0; 169 | while($retry++ < ENV_NUM_HTTP11_RETRY) { 170 | $locations = parse_header($head, "location"); 171 | if(count($locations) > 0) { 172 | $method = "GET"; 173 | $uris = parse_uri($locations[0], $uris); 174 | $query = ""; 175 | $cookie = viewcard_update_cookie($head, $cookie); 176 | list($head, $body) = viewcard_http11($method, $uris, $query, $cookie); 177 | } 178 | } 179 | 180 | // お支払日は4日であると仮定する 181 | if(strpos($body, "ご請求はございません。") !== false) { 182 | $body = ""; 183 | $account["paydate"] = substr(ENV_STR_DATE_TODAY, 0, 6) . "04"; 184 | } 185 | 186 | $body_old = $body; 187 | 188 | // 明細CSVをダウンロードする 189 | $forms = parse_tag($body, "form"); 190 | $c = parse_tag_search($forms, "name", "Form1"); 191 | if($c != -1) { 192 | $inputs = parse_tag($forms[$c]["innerHTML"], "input"); 193 | $queries = array(); 194 | foreach($inputs as $input) if($input["name"] != "") $queries[$input["name"]] = urlencode($input["name"]) . "=" . urlencode($input["value"]); 195 | $queries["DdlCardNO"] = "DdlCardNO=" . $account["id"]; 196 | $queries["BtnCsvDownloadTop.x"] = "BtnCsvDownloadTop.x=1"; 197 | $queries["BtnCsvDownloadTop.y"] = "BtnCsvDownloadTop.y=1"; 198 | if(isset($queries["BtnCsvDownloadTop"]) == true) unset($queries["BtnCsvDownloadTop"]); 199 | if(isset($queries["BtnCsvDownloadBottom"]) == true) unset($queries["BtnCsvDownloadBottom"]); 200 | if(isset($queries["BtnPdfDownloadTop"]) == true) unset($queries["BtnPdfDownloadTop"]); 201 | if(isset($queries["BtnPdfDownloadBottom"]) == true) unset($queries["BtnPdfDownloadBottom"]); 202 | if(isset($queries["BtnList"]) == true) unset($queries["BtnList"]); 203 | 204 | $method = $forms[$c]["method"]; 205 | $uris = parse_uri($forms[$c]["action"], $uris); 206 | $query = implode("&", $queries); 207 | $cookie = viewcard_update_cookie($head, $cookie); 208 | list($head, $body) = viewcard_http11($method, $uris, $query, $cookie); 209 | } 210 | 211 | if($body == "" || strpos($head, "Content-Type: text/html") === false) { 212 | $creditcardmsgsrsv1 .= "<CCSTMTTRNRS>"; 213 | $creditcardmsgsrsv1 .= "\r\n"; 214 | $creditcardmsgsrsv1 .= "<TRNUID>0</TRNUID>"; 215 | $creditcardmsgsrsv1 .= "\r\n"; 216 | $creditcardmsgsrsv1 .= "<STATUS><CODE>0</CODE><SEVERITY>INFO</SEVERITY></STATUS>"; 217 | $creditcardmsgsrsv1 .= "\r\n"; 218 | $creditcardmsgsrsv1 .= "<CCSTMTRS>"; 219 | $creditcardmsgsrsv1 .= "\r\n"; 220 | $creditcardmsgsrsv1 .= "<CURDEF>" . ENV_STR_OFX_CURRENCY_JPY . "</CURDEF>"; 221 | $creditcardmsgsrsv1 .= "\r\n"; 222 | $creditcardmsgsrsv1 .= "<CCACCTFROM>"; 223 | $creditcardmsgsrsv1 .= "<ACCTID>" . $account["acctid"] . "</ACCTID>"; 224 | $creditcardmsgsrsv1 .= "</CCACCTFROM>"; 225 | $creditcardmsgsrsv1 .= "\r\n"; 226 | $creditcardmsgsrsv1 .= viewcard_parse_csv($body, $account); 227 | $creditcardmsgsrsv1 .= "</CCSTMTRS>"; 228 | $creditcardmsgsrsv1 .= "\r\n"; 229 | $creditcardmsgsrsv1 .= "</CCSTMTTRNRS>"; 230 | $creditcardmsgsrsv1 .= "\r\n"; 231 | } 232 | 233 | $body = $body_old; 234 | } 235 | 236 | $creditcardmsgsrsv1 .= "</CREDITCARDMSGSRSV1>"; 237 | $creditcardmsgsrsv1 .= "\r\n"; 238 | 239 | // 実行時間(タイムアウト)を再設定する 240 | @set_time_limit(ENV_NUM_TIMEOUT); 241 | 242 | // ログアウトする 243 | $as = parse_tag($body, "a"); 244 | $c = parse_tag_search($as, "innerHTML", "ログアウト"); // ログアウト 245 | if($c != -1) { 246 | $method = "GET"; 247 | $uris = parse_uri($as[$c]["href"], $uris); 248 | $query = ""; 249 | $cookie = viewcard_update_cookie($head, $cookie); 250 | list($head, $body) = viewcard_http11($method, $uris, $query, $cookie); 251 | } 252 | 253 | // リダイレクトする 254 | $forms = parse_tag($body, "form"); 255 | $c = parse_tag_search($forms, "name", "frmMain"); 256 | if($c != -1) { 257 | $inputs = parse_tag($forms[$c]["innerHTML"], "input"); 258 | $queries = array(); 259 | foreach($inputs as $input) if($input["name"] != "") $queries[$input["name"]] = urlencode($input["name"]) . "=" . urlencode($input["value"]); 260 | $queries["Logout.x"] = "Logout.x=0"; 261 | $queries["Logout.y"] = "Logout.y=0"; 262 | 263 | $method = $forms[$c]["method"]; 264 | $uris = parse_uri($forms[$c]["action"], $uris); 265 | $query = implode("&", $queries); 266 | $cookie = viewcard_update_cookie($head, $cookie); 267 | list($head, $body) = viewcard_http11($method, $uris, $query, $cookie); 268 | } 269 | 270 | // リダイレクトする 271 | $retry = 0; 272 | while($retry++ < ENV_NUM_HTTP11_RETRY) { 273 | $locations = parse_header($head, "location"); 274 | if(count($locations) > 0) { 275 | $method = "GET"; 276 | $uris = parse_uri($locations[0], $uris); 277 | $query = ""; 278 | $cookie = viewcard_update_cookie($head, $cookie); 279 | list($head, $body) = viewcard_http11($method, $uris, $query, $cookie); 280 | } 281 | } 282 | 283 | // OFXファイルを出力する 284 | $resp["status"] = ENV_NUM_STATUS_SUCCESS; 285 | if(strpos($creditcardmsgsrsv1, "<BANKTRANLIST>") === false) { 286 | // 明細が存在しない場合 287 | $resp["ofx"] = generate_ofx($resp["status"]); 288 | } else { 289 | // 明細が存在する場合 290 | $resp["ofx"] = generate_ofx($resp["status"], $creditcardmsgsrsv1); 291 | } 292 | } 293 | return $resp; 294 | 295 | // HTTP/1.1 296 | function viewcard_http11($method, $uris, $query = "", $cookie = "") { 297 | $ret = "INVALID HOST"; 298 | if(preg_match("/^viewsnet\.jp$/", $uris["host"]) > 0 || (strtoupper($method) == "GET" && preg_match("/\.jreast\.co\.jp$/", $uris["host"]) > 0)) $ret = http11(strtoupper($method), $uris["scheme"], $uris["host"], 0, $uris["path"], $query, "", $cookie); 299 | return explode("\r\n\r\n", $ret, 2); 300 | } 301 | 302 | function viewcard_update_cookie($head, $cookie) { 303 | return update_cookie(array("BIGipServerPL-VNWEB-PC_WAF-TCP80", "VIEWSNET_WEB", "ASP.NET_SessionId", "citrix_ns_id", "citrix_ns_id_.viewsnet.jp_%2F_wat"), parse_header($head, "set-cookie"), $cookie); 304 | } 305 | 306 | function viewcard_parse_csv($str, $account) { 307 | $ret = ""; 308 | $lines = parse_csv(mb_convert_string($str)); 309 | $cds = array(); 310 | $cds_balamt = "0"; 311 | $cds_paydate = $account["paydate"]; 312 | $cds_s = ""; 313 | $cds_e = ""; 314 | $cd_date = ""; 315 | $cd_num = 0; 316 | $ledge_balamt = 0; 317 | 318 | foreach($lines as $line) { 319 | $cd = array(); 320 | 321 | if(count($line) == 2) { 322 | switch($line[0]) { 323 | case "お支払日": 324 | $cds_paydate = parse_date($line[1]); 325 | break; 326 | case "今回お支払金額": 327 | $cds_balamt = (string)(double)parse_amount($line[1]); 328 | $ledge_balamt = (double)$cds_balamt; 329 | break; 330 | case "会員番号": 331 | case "対象カード": 332 | default: 333 | break; 334 | } 335 | } else if(count($line) == 11 && $line[0] != "ご利用年月日") { 336 | 337 | // 日付を取得する 338 | $cd["DTPOSTED"] = parse_date($line[0]); 339 | if($line[1] == "ショッピングリボ弁済金") { 340 | $cd["DTPOSTED"] = $cds_paydate; 341 | $cd["TRNTYPE"] = ENV_STR_OFX_TRNTYPE_INT; 342 | } else { 343 | // PAYMENT固定とする 344 | $cd["TRNTYPE"] = ENV_STR_OFX_TRNTYPE_PAYMENT; 345 | } 346 | if($cds_s == "") $cds_s = $cd["DTPOSTED"]; 347 | $cds_e = $cd["DTPOSTED"]; 348 | 349 | // 通番を生成する 350 | if($cd["DTPOSTED"] == $cd_date) $cd_num++; else $cd_num = 0; 351 | 352 | // トランザクション番号を生成する 353 | $cd["FITID"] = $cd["DTPOSTED"] . sprintf("%04d", $account["id"]) . substr($account["paydate"], 4, 2) . "0" . sprintf("%05d", $cd_num); 354 | 355 | // 摘要を取得する 356 | $cd["NAME"] = $line[1]; 357 | 358 | // 金額を取得する 359 | $cd["TRNAMT"] = (string)(-1 * (double)parse_amount($line[7])); 360 | $ledge_balamt += (double)$cd["TRNAMT"]; 361 | 362 | // 残高を取得する 363 | $cd["MEMO"] = ($line[5] != ""? $line[5]: ENV_STR_OFX_MEMO); 364 | 365 | array_push($cds, $cd); 366 | $cd_date = $cd["DTPOSTED"]; 367 | } 368 | } 369 | 370 | if($cds_s == "") $cds_s = ENV_STR_DATE_TODAY; 371 | if($cds_e == "") $cds_e = ENV_STR_DATE_TODAY; 372 | if($cds_s > $cds_e) $cds_e = $cds_s; 373 | 374 | // クレジットカード支払請求を明細に追加する 375 | $i = count($cds); 376 | $cds[$i]["DTPOSTED"] = $cds_paydate; 377 | $cds[$i]["NAME"] = $account["name"]; 378 | $cds[$i]["MEMO"] = ENV_STR_OFX_MEMO; 379 | $cds[$i]["TRNAMT"] = $cds_balamt; 380 | $cds[$i]["TRNTYPE"] = ENV_STR_OFX_TRNTYPE_DIRECTDEBIT; 381 | $cds[$i]["FITID"] = $cds[$i]["DTPOSTED"] . sprintf("%04d", $account["id"]) . substr($account["paydate"], 4, 2) . "100000"; 382 | 383 | // BANKTRANLIST 384 | $ret .= "<BANKTRANLIST>"; 385 | $ret .= "\r\n"; 386 | $ret .= "<DTSTART>" . $cds_s . ENV_STR_OFX_TZ . "</DTSTART>"; 387 | $ret .= "<DTEND>" . $cds_e . ENV_STR_OFX_TZ . "</DTEND>"; 388 | $ret .= "\r\n"; 389 | 390 | foreach($cds as $cd) { 391 | $ret .= "<STMTTRN>"; 392 | $ret .= "<TRNTYPE>" . $cd["TRNTYPE"] . "</TRNTYPE>"; 393 | $ret .= "<DTPOSTED>" . $cd["DTPOSTED"] . ENV_STR_OFX_TZ . "</DTPOSTED>"; 394 | $ret .= "<TRNAMT>" . $cd["TRNAMT"] . "</TRNAMT>"; 395 | $ret .= "<FITID>" . $cd["FITID"] . "</FITID>"; 396 | $ret .= "<NAME>" . $cd["NAME"] . "</NAME>"; 397 | $ret .= "<MEMO>" . $cd["MEMO"] . "</MEMO>"; 398 | $ret .= "</STMTTRN>"; 399 | $ret .= "\r\n"; 400 | } 401 | 402 | $ret .= "</BANKTRANLIST>"; 403 | $ret .= "\r\n"; 404 | 405 | // 支払後残高を出力する 406 | $ret .= "<LEDGERBAL>"; 407 | $ret .= "<BALAMT>" . (string)$ledge_balamt . "</BALAMT>"; 408 | $ret .= "<DTASOF>" . ENV_STR_DATE_TODAY . ENV_STR_OFX_TZ . "</DTASOF>"; 409 | $ret .= "</LEDGERBAL>"; 410 | $ret .= "\r\n"; 411 | 412 | // カード名称を出力する 413 | if($account["acctname"] != "") { 414 | $ret .= "<MKTGINFO>" . $account["acctname"] . "</MKTGINFO>"; 415 | $ret .= "\r\n"; 416 | } 417 | 418 | return $ret; 419 | } 420 | 421 | ?> 422 | -------------------------------------------------------------------------------- /server/waon.inc: -------------------------------------------------------------------------------- 1 | <?php 2 | /* 3 | waon.inc: WAONネットステーションのHTMLよりOFXファイルを生成する 4 | Copyright (C) 2012-2017 Hiromu2000. All Rights Reserved. 5 | mailto:hiromu2000@hotmail.com 6 | Licensed under the GNU AGPLv3. 7 | */ 8 | 9 | $resp = array(); 10 | $ofx = ""; 11 | 12 | // 実行時間(タイムアウト)を再設定する 13 | @set_time_limit(ENV_NUM_TIMEOUT); 14 | 15 | // ログイン画面を取得する 16 | $uris = parse_uri($settings["home"]); 17 | $query = ""; 18 | $cookie = ""; 19 | list($head, $body) = waon_http11('GET', $uris, $query, $cookie); 20 | 21 | // ログインする 22 | $forms = parse_tag($body, "form"); 23 | $c = parse_tag_search($forms, "name", "loginForm"); 24 | $inputs = parse_tag($forms[$c]["innerHTML"], "input"); 25 | $queries = array(); 26 | foreach($inputs as $input) { 27 | if($input["name"] != "") { 28 | $queries[$input["name"]] = urlencode($input["name"]) . "=" . urlencode($input["value"]); 29 | } 30 | } 31 | $queries["cardNo1"] .= substr($ofxforms["cardNo"], 0, 4); 32 | $queries["cardNo2"] .= substr($ofxforms["cardNo"], 4, 4); 33 | $queries["cardNo3"] .= substr($ofxforms["cardNo"], 8, 4); 34 | $queries["cardNo4"] .= substr($ofxforms["cardNo"], 12, 4); 35 | $queries["secNo"] .= $ofxforms["secNo"]; 36 | $uris = parse_uri('/wmUseHistoryInq/login.do', $uris); 37 | $query = implode("&", $queries); 38 | $cookie = waon_update_cookie($head, $cookie); 39 | list($head, $body) = waon_http11('POST', $uris, $query, $cookie); 40 | 41 | if (strpos($body, "未実装") !== false) { 42 | // システムメンテナンス画面の場合 43 | $resp["status"] = ENV_NUM_STATUS_MAINTENANCE; 44 | $resp["method"] = $method; 45 | $resp["uri"] = $uris["scheme"] . "://" . $uris["host"] . $uris["path"]; 46 | $resp["query"] = $query; 47 | $resp["cookie"] = $cookie; 48 | $resp["head"] = $head; 49 | $resp["body"] = $body; 50 | $resp["ofx"] = generate_ofx($resp["status"]); 51 | } else if (strpos($body, "が正しく入力されていません。") !== false) { 52 | // ログイン失敗の場合 53 | $resp["status"] = ENV_NUM_STATUS_FAILURE; 54 | $resp["method"] = $method; 55 | $resp["uri"] = $uris["scheme"] . "://" . $uris["host"] . $uris["path"]; 56 | $resp["query"] = $query; 57 | $resp["cookie"] = $cookie; 58 | $resp["head"] = $head; 59 | $resp["body"] = $body; 60 | $resp["ofx"] = generate_ofx($resp["status"]); 61 | } else { 62 | // 今月の明細を処理する 63 | $cds = waon_parsedom($body); 64 | 65 | // 前月の明細を取得する 66 | $as = parse_tag($body, "a"); 67 | foreach($as as $a) { 68 | if (preg_match("/.*beforeMonth=1.*/", $a["href"])) { $url = $a["href"]; } 69 | } 70 | $urls = parse_url($url); 71 | $queries = array(); 72 | foreach(explode("&", htmlspecialchars_decode($urls["query"])) as $pair) { 73 | list($key, $value) = explode("=", $pair); 74 | $queries[$key] = $key . "=" . $value; 75 | } 76 | $uris = parse_uri($urls["path"], $uris); 77 | $query = implode("&", $queries); 78 | $cookie = waon_update_cookie($head, $cookie); 79 | list($head, $body) = waon_http11('GET', $uris, $query, $cookie); 80 | // 前月の明細を処理する 81 | $cds = array_merge($cds, waon_parsedom($body)); 82 | 83 | // ログアウトする 84 | $forms = parse_tag($body, "form"); 85 | $c = parse_tag_search($forms, "name", "logoutForm"); 86 | $inputs = parse_tag($forms[$c]["innerHTML"], "input"); 87 | $queries = array(); 88 | foreach($inputs as $input) { 89 | if($input["name"] != "") { 90 | $queries[$input["name"]] = urlencode($input["name"]) . "=" . urlencode($input["value"]); 91 | } 92 | } 93 | $uris = parse_uri('/wmUseHistoryInq/logout.do', $uris); 94 | $query = implode("&", $queries); 95 | $cookie = waon_update_cookie($head, $cookie); 96 | list($head, $body) = waon_http11('POST', $uris, $query, $cookie); 97 | 98 | // DOMツリーを生成 99 | $ofxdom = new ofxDOM("BANK", $settings["name"]); 100 | $ofxdom->setAcctfrom(array( 101 | "BANKID" => $settings["code"], 102 | "BRANCHID" => "0", 103 | "ACCTID" => $ofxforms["cardNo"], 104 | "ACCTTYPE" => "CHECKING" 105 | )); 106 | // 日付順に昇順ソート 107 | usort($cds, function($a, $b) { 108 | return $a['DTPOSTED'] > $b['DTPOSTED']; 109 | }); 110 | foreach($cds as $cd) { 111 | $ofxdom->addTran($cd); 112 | } 113 | // DTSTARTとDTENDを設定する 114 | $ofxdom->setDateRange(ENV_STR_DATE_PASTDAY . ENV_STR_OFX_TZ, ENV_STR_DATE_TODAY . ENV_STR_OFX_TZ); 115 | 116 | // 残高を処理。ただし、取得できないため、便宜上0円とする。 117 | $ofxdom->setBalance(array( 118 | 'BALAMT' => 0, 119 | 'DTASOF' => ENV_STR_DATE_TODAY . ENV_STR_OFX_TZ 120 | )); 121 | 122 | // FITIDを仕上げる 123 | $ofxdom->setFitid(); 124 | // XML DOMツリーを文字列に変換 125 | $xml = $ofxdom->getXML(); 126 | $resp["status"] = ENV_NUM_STATUS_SUCCESS; 127 | $resp["ofx"] = generate_ofx($mode, $xml); 128 | } 129 | return $resp; 130 | 131 | // HTTP/1.1 132 | function waon_http11($method, $uris, $query = "", $cookie = "") { 133 | $ret = "INVALID HOST"; 134 | if(preg_match("/\.waon\.com$/", $uris["host"]) > 0) $ret = http11(strtoupper($method), $uris["scheme"], $uris["host"], 0, $uris["path"], $query, "", $cookie); 135 | return explode("\r\n\r\n", $ret, 2); 136 | } 137 | function waon_update_cookie($head, $cookie) { 138 | return update_cookie(array( 139 | "JSESSIONID", 140 | "citrix_ns_id_.waon.com_%2F_wat", 141 | "Money-VS32-Cookie", 142 | "citrix_ns_id", 143 | "Waon-SSLVS04-Cookie", 144 | ), parse_header($head, "set-cookie"), $cookie); 145 | } 146 | 147 | function waon_parsedom($str) { 148 | $str = str_replace("Shift_JIS", "UTF-8", $str); 149 | $doc = new DOMDocument(); 150 | @$doc->loadHTML($str); 151 | $xpath = new DOMXPath($doc); 152 | $rows = $xpath->query("//table[@class='y']/tr"); 153 | 154 | $cds = array(); 155 | $nrow = $rows->length; 156 | 157 | for ($i=1; $i<$nrow; $i++) { 158 | $cd = array(); 159 | $cd["TRNTYPE"] = ENV_STR_OFX_TRNTYPE_DIRECTDEBIT; 160 | 161 | $row = $rows->item($i); 162 | $cols = $row->getElementsByTagName('td'); 163 | // 日付を取得する 164 | if (!preg_match("/([0-9]{4})\/([0-9]{1,2})\/([0-9]{1,2})/", trim($cols->item(0)->nodeValue), $matches)) { 165 | // 当月に明細が存在しなければスキップ 166 | break; 167 | } 168 | $cd["DTPOSTED"] = sprintf("%d%02d%02d", $matches[1], $matches[2], $matches[3]); 169 | $cd["DTPOSTED"] .= ENV_STR_OFX_TZ; 170 | 171 | // トランザクション番号(請求月とデータ種別)を生成する 172 | $cd["FITID"] = '000'; 173 | 174 | $cd['NAME'] = trim($cols->item(1)->nodeValue); 175 | $cd['TRNAMT'] = (int)parse_amount(trim($cols->item(2)->nodeValue)); 176 | if (preg_match("/支払/", $cols->item(3)->nodeValue) && !preg_match("/支払取消/", $cols->item(3)->nodeValue)) { 177 | $cd['TRNAMT'] *= -1; 178 | } 179 | array_push($cds, $cd); 180 | } 181 | return $cds; 182 | } 183 | ?> 184 | -------------------------------------------------------------------------------- /start_php.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | cd /d %~dp0 3 | php.exe -S 127.0.0.1:8000 4 | --------------------------------------------------------------------------------