You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

389 lines
15 KiB

<?php
/* ********** flow pattern for using sftp with edi_history
*
* 1. database query for "x12 Partners"
* -- get the partner name
* -- populate a "select" list with names
* -- "submit" runs script which gets url, password, etc and the sftp
* transfer for selected x12 partner
* -- put downloaded files in a designated directory e.g. history/sftp/
*
* 2 (alt) create php script to use most of edih_uploads.php function edih_upload_files()
* -- but skip the $_FILES array rewrite and testing, just test, match type and store
* -- maybe call it edih_sftp_upload()
*
* 3. add if stanza to edih_main.php in section:
* if (strtolower($_SERVER['REQUEST_METHOD']) == 'post') {
* -- calls edih_io.php function edih_disp_sftp_upload()
* -- remove the files from the download directory
* (alt) -- this is where you would call maybe edih_sftp_upload()
*
* 4. At this point the sftp files will be in the edi/history/[type] directories
* and the "Process" button will run the script to parse the files and create csv table rows
*
*/
// comment out below exit when need to use this script
exit;
/* ** add this function to edih_uploads.php
* -- or work it into edih_upload_files(), since it is almost a direct copy
*
*/
function edih_upload_sftp()
{
//
$html_str = '';
//
$sftp_dir = 'path/to/dir';
// if ($_FILES) ) {
//csv_edihist_log('Error: upload files indicated, but none received.');
//return false;
//} elseif
if (is_dir($sftp_dir) && is_readable($sftp_dir)) {
$sftp_dir = realpath($sftp_dir);
$fn_ar = scandir($sftp_dir);
} else {
$html_str = 'unable to read the directory for sftp file uploads <br />';
csv_edihist_log('unable to read the directory for sftp file uploads');
return $html_str;
}
//
$m_types = array('application/octet-stream', 'text/plain', 'application/zip', 'application/x-zip-compressed');
//
// some unwanted file extensions that might be accidentally included in upload files
$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';
// we get the parameters here to send to ibr_upload_match_file()
$param_ar = csv_parameters();
//if ( class_exists('finfo') )
foreach ($fn_ar as $idx => $fn) {
$fa = array();
$fa['tmp_name'] = tempnam($sftp_dir . DS . $fn, 'x12_');
$fa['name'] = $sftp_dir . DS . $fn;
$fa['type'] = mime_content_type($sftp_dir . DS . $fn);
$fa['size'] = filesize($sftp_dir . DS . $fn);
// now do verifications
if (!in_array($fa['type'], $m_types)) {
//$html_str .= "Error: mime-type {$fa['type']} not accepted for {$fa['name']} <br />" . PHP_EOL;
$f_ar['reject'][] = array('name' => $fa['name'],'comment' => 'mime-type ' . $fa['type']);
csv_edihist_log('edih_upload_sftp: error mime-type ' . $fa['name'] . ' mime-type ' . $fa['type']);
unset($fn_ar[$idx]);
continue;
}
// verify that we have a usable name
$fext = (strpos($fa['name'], '.')) ? pathinfo($fa['name'], PATHINFO_EXTENSION) : '';
if ($fext && preg_match('/' . $ext_types . '\?/i', $fext)) {
//$html_str .= 'Error: uploaded_file error for '.$fa['name'].' extension '.$fext.'<br />'. PHP_EOL;
$f_ar['reject'][] = array('name' => $fa['name'],'comment' => 'extension ' . $fext);
csv_edihist_log('edih_upload_sftp: _FILES error name ' . $fa['name'] . ' extension ' . $fext);
unset($fn_ar[$idx]);
continue;
}
if (is_string($fa['name'])) {
// check for null byte in file name, linux hidden file, directory
if (strpos($fa['name'], '.') === 0 || strpos($fa['name'], "\0") !== false || strpos($fa['name'], "./") !== false) {
//$html_str .= "Error: uploaded_file error for " . $fa['name'] . "<br />". PHP_EOL;
$fname = preg_replace("/[^a-zA-Z0-9_.-]/", "_", $fa['name']);
$f_ar['reject'][] = array('name' => $fname,'comment' => 'null byte, hidden, invalid');
csv_edihist_log('edih_upload_sftp: null byte, hidden, invalid ' . $fname);
unset($fn_ar[$idx]);
continue;
}
// replace spaces in file names -- should not happen, but response files from payers might have spaces
// $fname = preg_replace("/[^a-zA-Z0-9_.-]/","_",$fname);
$fa['name'] = str_replace(' ', '_', $fa['name']);
} else {
// name is not a string
//$html_str .= "Error: uploaded_file error for " . $fa['tmp_name'] . "<br />". PHP_EOL;
$f_ar['reject'][] = array('name' => (string)$fa['name'],'comment' => 'invalid name');
unset($fn_ar[$idx]);
continue;
}
if (!$fa['tmp_name'] || !$fa['size']) {
//$html_str .= "Error: file name or size error <br />" . PHP_EOL;
$f_ar['reject'][] = array('name' => (string)$fa['name'],'comment' => 'php file upload error');
unset($files[$uplkey][$idx]);
continue;
}
//
if (strpos(strtolower($fa['name']), '.zip') || strpos($fa['type'], 'zip')) {
//
$f_upl = edih_ziptoarray($fa['tmp_name'], $param_ar, false);
//
// put them in the correct type array
if (is_array($f_upl) && count($f_upl)) {
foreach ($f_upl as $tp => $fz) {
if ($tp == 'reject') {
if (isset($f_ar['reject']) && is_array($fz)) {
array_merge($f_ar['reject'], $fz);
} else {
$f_ar['reject'] = (is_array($fz)) ? $fz : array();
}
} else {
// expect $fz to be an array of file names
foreach ($fz as $zf) {
$f_ar[$tp][] = $zf;
$p_ct++;
}
}
}
} else {
// nothing good from edih_ziptoarray()
// $html_str .= "error with zip file or no files accepted for " . $fa['name'] . "<br />" .PHP_EOL;
$f_ar['reject'][] = array('name' => $fa['name'],'comment' => 'error with zip archive');
unset($files[$uplkey][$idx]);
}
// continue, since we have done everything that would happen below
continue;
}
//
$f_upl = edih_upload_match_file($param_ar, $fa);
//
if (is_array($f_upl) && count($f_upl) > 0) {
$f_ar[$f_upl['type']][] = $f_upl['name'];
$p_ct++;
} else {
// verification failed
csv_edihist_log('edih_upload_file: verification failed for ' . $fa['name']);
$f_ar['reject'][] = array('name' => $fa['name'], 'comment' => 'verification failed');
unset($fn_ar[$idx]);
}
} // end foreach($files[$uplkey] as $idx=>$fa)
//
$f_ar['remark'][] = "Received $f_ct files, accepted $p_ct" . PHP_EOL;
return $f_ar;
}
/* ** add this function to edih_io.php */
function edih_disp_sftp_upload()
{
// sftp file upload
// imaginary form and POST values
$str_html = '';
if (isset($_POST['post_sftp'])) {
$la = (isset($_POST['post_sftp'])) ? filter_input(INPUT_POST, 'post_sftp', FILTER_DEFAULT) : '';
$x12ptnr = (isset($_POST['sftp_select'])) ? filter_input(INPUT_POST, 'sftp_select', FILTER_DEFAULT) : '';
//
if (($la == 'get_sftp') && $x12ptnr) {
// yet to be written -- gets x12 partner info and does sftp download
$is_sftp = edih_sftp_connect($x12ptnr);
//
$f_array = ($is_sftp) ? edih_upload_sftp() : false;
if (is_array($f_array) && count($f_array)) {
$str_html .= edih_sort_upload($f_array);
} else {
$str_html .= "sftp connection did not get any files <br />" . PHP_EOL;
}
} else {
$str_html .= "sftp file transfer invalid input <br />" . PHP_EOL;
}
//
return $str_html;
}
}
/* ** edih_view.php needs a form to give user control over sftp uploads */
// a select list of x12 partners and submit button and process button
// append output of edih_disp_sftp_upload() to displayed file list
/**
* Unattended SFTP host operations using phpseclib.
*
* Copyright (C) 2014 MD Support <mdsupport@users.sourceforge.net>
*
* LICENSE: This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://opensource.org/licenses/gpl-license.php>.
*
* @package OpenEMR
* @author MD Support <mdsupport@users.sourceforge.net>
*
* Following parameters may be provided :
* 1. actn - get or put
* 2. Interface with Procedure providers : ppid
* 3. Single host definition : host, port, user, pass, fdir, pdir
* 4. ldir - local directory
* 5. sub - 'ppid'/'host'/'fdir'/'pdir' to be used as subdir of ldir
**/
if (php_sapi_name() == 'cli') {
parse_str(implode('&', array_slice($argv, 1)), $_GET);
$_SERVER['REQUEST_URI'] = $_SERVER['PHP_SELF'];
$_SERVER['SERVER_NAME'] = 'localhost';
$backpic = "";
$ignoreAuth = 1;
// Since from command line, set $sessionAllowWrite since need to set site_id session and no benefit to set to false
$sessionAllowWrite = true;
}
$get_count = extract($_GET, EXTR_OVERWRITE);
// Following breaks link to OpenEMR structure dependency - assumes phpseclib is subdir
$script_dir = dirname(__FILE__);
ini_set('include_path', ini_get('include_path') . PATH_SEPARATOR . "$script_dir/phpseclib");
require_once("$script_dir/phpseclib/Net/SFTP.php");
function get_openemr_globals($libdir)
{
if (!isset($site)) {
$_GET['site'] = 'default';
}
require_once("$libdir/../interface/globals.php");
}
function sftp_status($msg, $val)
{
if (php_sapi_name() == 'cli') {
fwrite(STDOUT, xl($msg) . ' ' . $val . PHP_EOL);
}
}
$exitmsgs = array (
0 => ''
,1 => 'Missing/Invalid parameter(s) - SFTP host definition, actn, ldir'
,2 => 'File Transfer error(s)'
);
// OpenEMR specific mappings. $sub works with procedure_providers fields
$submap = array(
'ppid' => 'ppid'
,'host' => 'remote_host'
,'fdir' => 'results_path'
,'pdir' => 'orders_path'
);
$pathmap = array(
'get' => 'results_path'
,'put' => 'orders_path'
);
$exitcd = 0;
// Perform parameter-driven actions
if (isset($ppid)) {
if (!isset($srcdir)) {
get_openemr_globals($script_dir);
}
$rsql = "SELECT * FROM procedure_providers WHERE protocol=? ";
$rprm = array('SFTP');
if ($ppid != "*") {
$rsql .= " AND ppid=?";
$rprm[] = $ppid;
}
$rs = sqlStatement($rsql, $rprm);
while ($rsrec = sqlFetchArray($rs)) {
$sftp_hosts[] = $rsrec;
}
} else { // fill in host detais from parameters
if (isset($fhost) && isset($user) && (isset($fdir) || isset($pdir))) {
$sftp_hosts[] = array (
'remote_host' => $host
,'port' => $port
,'login' => $user
,'password' => $pass
,'results_path' => $fdir
,'orders_path' => $pdir
);
}
}
if (
(!isset($sftp_hosts)) || (!isset($ldir)) ||
(((!isset($actn)) || (!(in_array($actn, array_keys($pathmap)))))) ||
(((isset($sub)) && (!(in_array($sub, array_keys($submap))))))
) {
$exitcd = 1;
}
if (!$exitcd) {
foreach ($sftp_hosts as $sftp_host) {
$wrk = explode(':', $sftp_host['remote_host']);
$sftp_host['remote_host'] = $wrk[0];
if (!isset($sftp_host['port'])) {
$sftp_host['port'] = (isset($wrk[1]) ? $wrk[1] : '22');
}
$cn = new \phpseclib\Net\SFTP($sftp_host['remote_host'], $sftp_host['port']);
if (!$cn->login($sftp_host['login'], $sftp_host['password'])) {
sftp_status('Login error', $sftp_host['remote_host'] . ':' . $sftp_host['port']);
} else {
$sdir = '';
if ((isset($sub)) && (isset($sftp_host[$submap[$sub]]))) {
$sdir = '/' . $sftp_host[$submap[$sub]];
}
// Get the list of files. TBD: Overwrite protection.
if ($actn == 'get') {
$dir_from = $sftp_host[$pathmap[$actn]];
$dir_to = ($ldir . $sdir);
$full_list = $cn->rawlist($dir_from);
foreach ($full_list as $file_name => $file_rec) {
if ($file_rec['type'] == NET_SFTP_TYPE_REGULAR) {
$dir_list[] = $file_name;
}
}
} else {
$dir_to = $sftp_host[$pathmap[$actn]];
$dir_from = ($ldir . $sdir);
$full_list = new DirectoryIterator($dir_from);
foreach ($full_list as $fileinfo) {
if ($fileinfo->isFile()) {
$dir_list[] = $fileinfo->getFilename();
}
}
}
// Transfer each file
if (isset($dir_list)) {
foreach ($dir_list as $dir_file) {
// Skip directories
// mdsupport - now $dir_list should have only valid file names
// if (($dir_file == '.') || ($dir_file == '..')) {}
// else {
if ($actn == 'get') {
$sftp_ok = $cn->get(($dir_from . '/' . $dir_file), ($dir_to . '/' . $dir_file));
if ($sftp_ok) {
$sftp_del = $cn->delete(($dir_from . '/' . $dir_file));
}
} else {
$sftp_ok = $cn->put(($dir_to . '/' . $dir_file), ($dir_from . '/' . $dir_file), NET_SFTP_LOCAL_FILE);
if ($sftp_ok) {
$sftp_del = unlink(($dir_from . '/' . $dir_file));
}
}
sftp_status('File transfer ' . ($sftp_ok ? 'ok' : 'error'), ($dir_from . '/' . $dir_file));
if (isset($sftp_del) && (!$sftp_del)) {
sftp_status('File deletion error', $dir_file);
}
if ((!$sftp_ok) || (isset($sftp_del) && (!$sftp_del))) {
$exitcd = 2;
}
// }
}
}
}
sftp_status('Host action complete', " : $actn files from " . $sftp_host['remote_host'] . ':' . $sftp_host['port'] . " $dir_to");
}
}
if (php_sapi_name() == 'cli') {
fwrite(($exitcd ? STDERR : STDOUT), xl($exitmsgs[$exitcd]) . PHP_EOL);
exit($exitcd);
}