Eye module improvements with other minor improvements
[openemr.git] / library / edihistory / test_edih_sftp_files.php
blob0d6a7f0668a6591e021f8ac548b9ded42f84e5a1
1 <?php
2 /* ********** flow pattern for using sftp with edi_history
4 * 1. database query for "x12 Partners"
5 * -- get the partner name
6 * -- populate a "select" list with names
7 * -- "submit" runs script which gets url, password, etc and the sftp
8 * transfer for selected x12 partner
9 * -- put downloaded files in a designated directory e.g. history/sftp/
11 * 2 (alt) create php script to use most of edih_uploads.php function edih_upload_files()
12 * -- but skip the $_FILES array rewrite and testing, just test, match type and store
13 * -- maybe call it edih_sftp_upload()
15 * 3. add if stanza to edih_main.php in section:
16 * if (strtolower($_SERVER['REQUEST_METHOD']) == 'post') {
17 * -- calls edih_io.php function edih_disp_sftp_upload()
18 * -- remove the files from the download directory
19 * (alt) -- this is where you would call maybe edih_sftp_upload()
21 * 4. At this point the sftp files will be in the edi/history/[type] directories
22 * and the "Process" button will run the script to parse the files and create csv table rows
26 /* ** add this function to edih_uploads.php
27 * -- or work it into edih_upload_files(), since it is almost a direct copy
30 function edih_upload_sftp()
33 $html_str = '';
35 $sftp_dir = 'path/to/dir';
36 // if ($_FILES) ) {
37 //csv_edihist_log('Error: upload files indicated, but none received.');
38 //return false;
39 //} elseif
40 if (is_dir($sftp_dir) && is_readable($sftp_dir)) {
41 $sftp_dir = realpath($sftp_dir);
42 $fn_ar = scandir($sftp_dir);
43 } else {
44 $html_str = 'unable to read the directory for sftp file uploads <br />';
45 csv_edihist_log('unable to read the directory for sftp file uploads');
46 return $html_str;
50 $m_types = array('application/octet-stream', 'text/plain', 'application/zip', 'application/x-zip-compressed');
52 // some unwanted file extensions that might be accidentally included in upload files
53 $ext_types = 'sh|asp|html|htm|cm|js|xml|jpg|png|tif|xpm|pdf|php|py|pl|tcl|doc|pub|ppt|xls|xla|vsd|rtf|odt|ods|odp';
54 // we get the parameters here to send to ibr_upload_match_file()
55 $param_ar = csv_parameters();
56 //if ( class_exists('finfo') )
57 foreach ($fn_ar as $idx => $fn) {
58 $fa = array();
59 $fa['tmp_name'] = tempnam($sftp_dir.DS.$fn, 'x12_');
60 $fa['name'] = $sftp_dir.DS.$fn;
61 $fa['type'] = mime_content_type($sftp_dir.DS.$fn);
62 $fa['size'] = filesize($sftp_dir.DS.$fn);
63 // now do verifications
64 if (!in_array($fa['type'], $m_types)) {
65 //$html_str .= "Error: mime-type {$fa['type']} not accepted for {$fa['name']} <br />" . PHP_EOL;
66 $f_ar['reject'][] = array('name'=>$fa['name'],'comment'=>'mime-type '.$fa['type']);
67 csv_edihist_log('edih_upload_sftp: error mime-type '.$fa['name'].' mime-type '.$fa['type']);
68 unset($fn_ar[$idx]);
69 continue;
72 // verify that we have a usable name
73 $fext = (strpos($fa['name'], '.')) ? pathinfo($fa['name'], PATHINFO_EXTENSION) : '';
74 if ($fext && preg_match('/'.$ext_types.'\?/i', $fext)) {
75 //$html_str .= 'Error: uploaded_file error for '.$fa['name'].' extension '.$fext.'<br />'. PHP_EOL;
76 $f_ar['reject'][] = array('name'=>$fa['name'],'comment'=>'extension '.$fext);
77 csv_edihist_log('edih_upload_sftp: _FILES error name '.$fa['name'].' extension '.$fext);
78 unset($fn_ar[$idx]);
79 continue;
82 if (is_string($fa['name'])) {
83 // check for null byte in file name, linux hidden file, directory
84 if (strpos($fa['name'], '.') === 0 || strpos($fa['name'], "\0") !== false || strpos($fa['name'], "./") !== false) {
85 //$html_str .= "Error: uploaded_file error for " . $fa['name'] . "<br />". PHP_EOL;
86 $fname = preg_replace("/[^a-zA-Z0-9_.-]/", "_", $fa['name']);
87 $f_ar['reject'][] = array('name'=>$fname,'comment'=>'null byte, hidden, invalid');
88 csv_edihist_log('edih_upload_sftp: null byte, hidden, invalid '.$fname);
89 unset($fn_ar[$idx]);
90 continue;
93 // replace spaces in file names -- should not happen, but response files from payers might have spaces
94 // $fname = preg_replace("/[^a-zA-Z0-9_.-]/","_",$fname);
95 $fa['name'] = str_replace(' ', '_', $fa['name']);
96 } else {
97 // name is not a string
98 //$html_str .= "Error: uploaded_file error for " . $fa['tmp_name'] . "<br />". PHP_EOL;
99 $f_ar['reject'][] = array('name'=>(string)$fa['name'],'comment'=>'invalid name');
100 unset($fn_ar[$idx]);
101 continue;
104 if (!$fa['tmp_name'] || !$fa['size']) {
105 //$html_str .= "Error: file name or size error <br />" . PHP_EOL;
106 $f_ar['reject'][] = array('name'=>(string)$fa['name'],'comment'=>'php file upload error');
107 unset($files[$uplkey][$idx]);
108 continue;
112 if (strpos(strtolower($fa['name']), '.zip') || strpos($fa['type'], 'zip')) {
114 $f_upl = edih_ziptoarray($fa['tmp_name'], $param_ar, false);
116 // put them in the correct type array
117 if (is_array($f_upl) && count($f_upl)) {
118 foreach ($f_upl as $tp => $fz) {
119 if ($tp == 'reject') {
120 if (isset($f_ar['reject']) && is_array($fz)) {
121 array_merge($f_ar['reject'], $fz);
122 } else {
123 $f_ar['reject'] = (is_array($fz)) ? $fz : array();
125 } else {
126 // expect $fz to be an array of file names
127 foreach ($fz as $zf) {
128 $f_ar[$tp][] = $zf;
129 $p_ct ++;
133 } else {
134 // nothing good from edih_ziptoarray()
135 // $html_str .= "error with zip file or no files accepted for " . $fa['name'] . "<br />" .PHP_EOL;
136 $f_ar['reject'][] = array('name'=>$fa['name'],'comment'=>'error with zip archive');
137 unset($files[$uplkey][$idx]);
140 // continue, since we have done everything that would happen below
141 continue;
145 $f_upl = edih_upload_match_file($param_ar, $fa);
147 if (is_array($f_upl) && count($f_upl) > 0) {
148 $f_ar[$f_upl['type']][] = $f_upl['name'];
149 $p_ct++;
150 } else {
151 // verification failed
152 csv_edihist_log('edih_upload_file: verification failed for '. $fa['name']);
153 $f_ar['reject'][] = array('name'=>$fa['name'], 'comment'=>'verification failed');
154 unset($fn_ar[$idx]);
156 } // end foreach($files[$uplkey] as $idx=>$fa)
158 $f_ar['remark'][] = "Received $f_ct files, accepted $p_ct" . PHP_EOL;
159 return $f_ar;
162 /* ** add this function to edih_io.php */
163 function edih_disp_sftp_upload() {
164 // sftp file upload
165 // imaginary form and POST values
166 $str_html = '';
167 if (isset($_POST['post_sftp'])) {
168 $la = (isset($_POST['post_sftp'])) ? filter_input(INPUT_POST, 'post_sftp', FILTER_DEFAULT) : ;
169 $x12ptnr = (isset($_POST['sftp_select'])) ? filter_input(INPUT_POST, 'sftp_select', FILTER_DEFAULT) :;
171 if (($la == 'get_sftp') && $x12ptnr) {
172 // yet to be written -- gets x12 partner info and does sftp download
173 $is_sftp = edih_sftp_connect($x12ptnr);
175 $f_array = ($is_sftp) ? edih_upload_sftp() : false;
176 if (is_array($f_array) && count($f_array)) {
177 $str_html .= edih_sort_upload($f_array);
178 } else {
179 $str_html .= "sftp connection did not get any files <br />".PHP_EOL;
181 } else {
182 $str_html .= "sftp file transfer invalid input <br />" . PHP_EOL;
186 return $str_html;
189 /* ** edih_view.php needs a form to give user control over sftp uploads */
190 // a select list of x12 partners and submit button and process button
191 // append output of edih_disp_sftp_upload() to displayed file list
194 * Unattended SFTP host operations using phpseclib.
196 * Copyright (C) 2014 MD Support <mdsupport@users.sourceforge.net>
198 * LICENSE: This program is free software; you can redistribute it and/or
199 * modify it under the terms of the GNU General Public License
200 * as published by the Free Software Foundation; either version 2
201 * of the License, or (at your option) any later version.
202 * This program is distributed in the hope that it will be useful,
203 * but WITHOUT ANY WARRANTY; without even the implied warranty of
204 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
205 * GNU General Public License for more details.
206 * You should have received a copy of the GNU General Public License
207 * along with this program. If not, see <http://opensource.org/licenses/gpl-license.php>.
209 * @package OpenEMR
210 * @author MD Support <mdsupport@users.sourceforge.net>
212 * Following parameters may be provided :
213 * 1. actn - get or put
214 * 2. Interface with Procedure providers : ppid
215 * 3. Single host definition : host, port, user, pass, fdir, pdir
216 * 4. ldir - local directory
217 * 5. sub - 'ppid'/'host'/'fdir'/'pdir' to be used as subdir of ldir
221 if (php_sapi_name() == 'cli') {
222 parse_str(implode('&', array_slice($argv, 1)), $_GET);
223 $_SERVER['REQUEST_URI']=$_SERVER['PHP_SELF'];
224 $_SERVER['SERVER_NAME']='localhost';
225 $backpic = "";
226 $ignoreAuth=1;
229 $get_count = extract($_GET, EXTR_OVERWRITE);
230 // Following breaks link to OpenEMR structure dependency - assumes phpseclib is subdir
231 $script_dir = dirname(__FILE__);
232 ini_set('include_path', ini_get('include_path') . PATH_SEPARATOR . "$script_dir/phpseclib");
233 require_once("$script_dir/phpseclib/Net/SFTP.php");
234 function get_openemr_globals($libdir)
236 if (!isset($site)) {
237 $_GET['site'] = 'default';
240 require_once("$libdir/../interface/globals.php");
242 function sftp_status($msg, $val)
244 if (php_sapi_name() == 'cli') {
245 fwrite(STDOUT, xl($msg).' '.$val.PHP_EOL);
248 $exitmsgs = array (
249 0 => ''
250 ,1 => 'Missing/Invalid parameter(s) - SFTP host definition, actn, ldir'
251 ,2 => 'File Transfer error(s)'
253 // OpenEMR specific mappings. $sub works with procedure_providers fields
254 $submap = array(
255 'ppid' => 'ppid'
256 ,'host' => 'remote_host'
257 ,'fdir' => 'results_path'
258 ,'pdir' => 'orders_path'
260 $pathmap = array(
261 'get' => 'results_path'
262 ,'put' => 'orders_path'
264 $exitcd = 0;
265 // Perform parameter-driven actions
266 if (isset($ppid)) {
267 if (!isset($srcdir)) {
268 get_openemr_globals($script_dir);
271 $rsql = "SELECT * FROM procedure_providers WHERE protocol=? ";
272 $rprm = array('SFTP');
273 if ($ppid !="*") {
274 $rsql .= " AND ppid=?";
275 $rprm[] = $ppid;
278 $rs = sqlStatement($rsql, $rprm);
279 while ($rsrec = sqlFetchArray($rs)) {
280 $sftp_hosts[] = $rsrec;
282 } else { // fill in host detais from parameters
283 if (isset($fhost) && isset($user) && (isset($fdir) || isset($pdir))) {
284 $sftp_hosts[] = array (
285 'remote_host' => $host
286 ,'port' => $port
287 ,'login' => $user
288 ,'password' => $pass
289 ,'results_path' => $fdir
290 ,'orders_path' => $pdir
295 if ((!isset($sftp_hosts)) || (!isset($ldir)) ||
296 (((!isset($actn)) || (!(in_array($actn, array_keys($pathmap)))))) ||
297 (((isset($sub)) && (!(in_array($sub, array_keys($submap))))))
299 $exitcd = 1;
302 if (!$exitcd) {
303 foreach ($sftp_hosts as $sftp_host) {
304 $wrk = explode(':', $sftp_host['remote_host']);
305 $sftp_host['remote_host'] = $wrk[0];
306 if (!isset($sftp_host['port'])) {
307 $sftp_host['port'] = (isset($wrk[1]) ? $wrk[1] : '22');
310 $cn = new \phpseclib\Net\SFTP($sftp_host['remote_host'], $sftp_host['port']);
311 if (!$cn->login($sftp_host['login'], $sftp_host['password'])) {
312 sftp_status('Login error', $sftp_host['remote_host'].':'.$sftp_host['port']);
313 } else {
314 $sdir = '';
315 if ((isset($sub)) && (isset($sftp_host[$submap[$sub]]))) {
316 $sdir = '/'.$sftp_host[$submap[$sub]];
319 // Get the list of files. TBD: Overwrite protection.
320 if ($actn == 'get') {
321 $dir_from = $sftp_host[$pathmap[$actn]];
322 $dir_to = ($ldir.$sdir);
323 $full_list = $cn->rawlist($dir_from);
324 foreach ($full_list as $file_name => $file_rec) {
325 if ($file_rec['type'] == NET_SFTP_TYPE_REGULAR) {
326 $dir_list[] = $file_name;
329 } else {
330 $dir_to = $sftp_host[$pathmap[$actn]];
331 $dir_from = ($ldir.$sdir);
332 $full_list = new DirectoryIterator($dir_from);
333 foreach ($full_list as $fileinfo) {
334 if ($fileinfo->isFile()) {
335 $dir_list[] = $fileinfo->getFilename();
340 // Transfer each file
341 if (isset($dir_list)) {
342 foreach ($dir_list as $dir_file) {
343 // Skip directories
344 // mdsupport - now $dir_list should have only valid file names
345 // if (($dir_file == '.') || ($dir_file == '..')) {}
346 // else {
347 if ($actn == 'get') {
348 $sftp_ok = $cn->get(($dir_from.'/'.$dir_file), ($dir_to.'/'.$dir_file));
349 if ($sftp_ok) {
350 $sftp_del = $cn->delete(($dir_from.'/'.$dir_file));
352 } else {
353 $sftp_ok = $cn->put(($dir_to.'/'.$dir_file), ($dir_from.'/'.$dir_file), NET_SFTP_LOCAL_FILE);
354 if ($sftp_ok) {
355 $sftp_del = unlink(($dir_from.'/'.$dir_file));
359 sftp_status('File transfer '.($sftp_ok ? 'ok' : 'error'), ($dir_from.'/'.$dir_file));
360 if (isset($sftp_del) && (!$sftp_del)) {
361 sftp_status('File deletion error', $dir_file);
364 if ((!$sftp_ok) || (isset($sftp_del) && (!$sftp_del))) {
365 $exitcd = 2;
368 // }
373 sftp_status('Host action complete', " : $actn files from ".$sftp_host['remote_host'].':'.$sftp_host['port']. " $dir_to");
377 if (php_sapi_name() == 'cli') {
378 fwrite(($exitcd ? STDERR : STDOUT), xl($exitmsgs[$exitcd]).PHP_EOL);
379 exit($exitcd);