Odyssey
hcuImages.i
1  <?php
2 
3 /*
4  * 2/20/18 MH
5  * Demo front and back images and the 'Image not found' image nochecksgl.gif moved
6  * from file path to cloudfront URL. Changed test for demo image is_readable to
7  * retrieve https headers and test for 200 OK status and file type image. Note that
8  * nocheckdbl.gif also moved to cloudfront, although it does not appear to be used
9  * at this time. Using hard-coded cloudfront domain instead of HB_ENV value because
10  * code is shared by both banking and admin, which doesn't have HB_ENV set.
11  */
12 /* This was ImageSOLO on mammoth
13  * For Odyssey, separate the retrieval logic from the security at the top
14  * Both Admin and Banking will have a container to handle security & credentials
15  * which then includes this library for the actual retrieval.
16  *
17  * NOTE: I am assuming the database handle $dbh is established before this include
18  * and that dms_imp_val.i has been included
19  *
20  * 3/6/17 All three formerly separate 'get raw image' scripts, RawImage, FedImage,
21  * and FiservImage have been converted to functions. Code tested & deployed on
22  * Mammoth, now porting to Odyssey.
23  *
24  * These are the surviving image vendors 2/14/2017
25  * ALLOYA
26  * SUNCORP still exists, but should move to ALLOYA
27  * CATALYST
28  * WESCORP still exists, but should move to CATALYST
29  * CORP1
30  * CORPAM
31  * CSI
32  * DEMO
33  * EASCORP
34  * FEDIMAGE
35  * FISERV
36  * FIS_IMGCTR
37  * IMAGEPOINT *new (Bluepoint) for Lone Star
38  * MAC
39  * MACIMGONLY
40  * MISSOURI
41  * MNIPC
42  * MVI
43  * PALMETTO
44  * SECORP
45  * SYNERGENT *NEW (VSOFT) for MISSFCU
46  * VOLCORP
47  */
48 
49 require_once('LogSSO.i');
50 require_once('cutrusted.i');
51 require_once('SSOEncryption.i');
52 
53 
54 if (!empty($adm)) {
55  $inc_adm = "&adm=1";
56 } else {
57  $inc_adm = "";
58 }
59 
60 if (empty($CKITEM) || empty($CKHASH)) {
61  # error Invalid Request (missing parameters)
62  NoImage("Invalid Request (missing parameters)", $adm);
63  exit;
64 }
65  #[CKITEM]= "${Cu}|${Cn}|${accounttype}|${cert}|${tracenumber}";
66  #[CKHASH]= sha1("${Cu}${Cn}${accounttype}${cert}${tracenumber}cierto");
67 
68  //$ckitem=hcu_decrypturl($CKITEM,$chk_key);
69 
70 /*
71  * On Mammoth, there are 3 ways to access the ImageSOLO check retrieval program.
72  *
73  * 1) From the Member History hcuHistory list, when the transaction represents a check
74  * clearing the check number is rendered as a link to ImageSOLO. Parameters passed on
75  * the URL represent the transaction in the database, NOT ENOUGH INFO to retrieve the
76  * check image independently.
77  *
78  * 2) From the Member hcuArchiveCheck script, which allows the member to key in info
79  * about a check clearing transaction. The transaction is generally presumed to have
80  * aged out of our database. Parameters passed on the URL include enough info to retrieve
81  * the image from the vendor. The ‘CKARCHIVE=1’ is included to notify ImageSOLO that
82  * it should use the info passed without looking up a transaction in the history table.
83  *
84  * 3) From the Admin MemCheck script, which allows admin staff to key in enough info
85  * to retrieve a check image. The ‘CKARCHIVE=1’ parameter is included in this method
86  * also.
87  *
88  * Note that Admin folks are allowed to key in some things that, on the member
89  * side, are only retrieved from the database, including MICR.
90  *
91  * In all 3 methods, the transaction info is passed in a pipe-delimited list as CKITEM,
92  * and because it contains potentially sensitive info, it is encrypted using the function
93  * hcu_encrypturl before passing on the URL line.
94  *
95  * Because ImageSOLO was called from both the admin side and the member side, we had to
96  * dance a little with the security and credentials. For Odyssey we decided to split
97  * the image retrieval portion of ImageSOLO into an include file hcuImages.i which could
98  * then be included from either the admin code line or the member code line.
99  *
100  * The idea was that the existing admin MemCheck would remain to allow admin folks to key
101  * in details about the image to be retrieved, and it would then post to a new, separate
102  * script which included hcuImages.i for the retrieval. This would leave the parameter
103  * passing intact and consistent across all 3 entry points. But the admin script was
104  * implemented instead as a single script, which means the parameters are not encoded
105  * for transport on the URL. hcuImages.i was also updated to eliminate the hcu_decrypturl
106  * call, because the new admin method doesn’t use it. This effectively breaks the code f
107  * rom the member side. The single script method may be workable for the hcuArhciveCheck
108  * script, but it does not work at all for the hcuHistory list.
109  *
110  * So, ugly as it is, we need to skip the hcu_decrypturl if CKARCHIVE is set and unpack
111  * parameters from CKITEM directly. But is CKARCHIVE is NOT set, we need to decrypt
112  * before unpacking.
113  * 3/15/17 MH Because hcuArchiveCheck also uses CKARCHIVE I added a distinct setting -
114  * aMemberImages sends CKARCHIVE=1 = use what you got as is,
115  * hcuArchiveCheck sends CKARCHIVE=2 = use what you got but hcu_decrypt first.
116  *
117  * Further coding exposes that....
118  * aMemberImages.prg introduced a new CHK_URL variable as the base URL for the link to
119  * the reverse side of the check. But the member side scripts have no knowledge of this
120  * new variable and there are no programmer notes or warnings about needing it to make
121  * things work.
122  * 3/15/17 MH Added CHK_URL to ImageSOLO.prg - not a bad way to solve the problem
123  * since now the admin and the member side use distinct scripts instead of sharing.
124  *
125  * Also, aMemberImages.prg script is setting values for $_REQUEST.
126  * $_REQUEST is a super-global, and we don't want to be messing with it. To resolve
127  * that problem, I am moving the dmsimpval stuff that sanitizes and imports variables
128  * from the $_REQUEST out of hcuImages.i. This means aMemberImages.prg need not muck
129  * with $_REQUEST and that ImageSOLO.prg must import the values from $_REQUEST. May
130  * need to adjust a little for where some of the other variables get set.
131  * 3/15/17 MH Notified Matt that setting $_REQUEST is not something we want to do and
132  * recoded to import functions to get what we need from $_REQUEST when necessary
133  *
134  * There are also some problems with the display block itself and understanding when
135  * to include style sheets, etc. To simplify this, the display block will move out of
136  * hcuImages.i and into the script which includes hcuImages.i - aMemberImages.prg,
137  * ImageSOLO.prg, and hcuArchiveCk.prg.
138  * 3/15/17 MH Left these as is - still don't like it but not much gain for the pain
139  * of moving.
140  *
141  *
142  * aMemberImages.prg also appears to have dropped code that sent special values for sortkey
143  * for specific vendors, like this:
144  *
145  * if ($img_vendor == 'FEDIMAGE') $sortkey = $check_number;
146  * elseif ($img_vendor == 'MAC') $sortkey = $check_micr;
147  * else $sortkey = '';
148  *
149  * Turns out this code dropped on the Mammoth upgrade - when switching from using ImageSRC
150  * to ImageSOLO. Dropping this code breaks those interfaces for some clients when retrieving
151  * images from the admin portal.
152  * 3/15/17 MH put this code back in place. No good way to test yet
153  *
154  */
155 
156  if ( $CKARCHIVE == "1" || $CKARCHIVE == "2") {
157  if ( $CKARCHIVE == "1" ) {
158  # got here from admin with all lookup parameters in CKITEM
159  // for this path all the transaction-specific information was passed in
160  $ckitem = hcu_decrypturl($CKITEM,$chk_key);
161  list ($iCu,$img,$check,$amount,$date,$rt,$micr,$iCn,$sk) = explode("|",$ckitem,9);
162  } elseif ( $CKARCHIVE == "2" ) {
163  # got here hcuArchiveCheck with all lookup parameters in CKITEM
164  # CKITEM is hcu_encrypted
165  $ckitem = hcu_decrypturl($CKITEM,$chk_key);
166  list ($iCu,$img,$check,$amount,$date,$rt,$micr,$iCn,$sk) = explode("|",$ckitem,9);
167  }
168  if ( $CKHASH != sha1("{$iCu}{$img}{$check}{$amount}{$date}{$rt}{$micr}{$CKARCHIVE}{$iCn}cierto") ) {
169  # error Invalid Request (corrupt parameters)
170  NoImage("Invalid Request (corrupt parameters) ", $adm);
171  exit;
172  }
173 
174  // But we need the image vendor credentials
175  $sql = "select ckhexkey, ckorgid, ckurl
176  from cuadmin where cu='$iCu'";
177 
178  $sth = db_query($sql,$dbh);
179  list ($ckhexkey, $ckorgid, $ckurl)=db_fetch_array($sth,0);
180  } else {
181  # got here from hcuHistory
182  # CKITEM hcu_encrypted for transport in the _REQUEST
183  $ckitem = hcu_decrypturl($CKITEM,$chk_key);
184  list ($iCu,$iCn,$iAt,$iCt,$iTrace) = explode("|",$ckitem,5);
185 
186  if ($CKHASH != sha1("${iCu}${iCn}${iAt}${iCt}${iTrace}cierto")) {
187  # error Invalid Request (corrupt parameters)
188  NoImage("Invalid Request (corrupt parameters) ", $adm);
189  exit;
190  }
191 
192  $sql = "select trim(rt) as rt,
193  trim(img) as img, ckhexkey, ckorgid, ckurl
194  from cuadmin where cu='$iCu'";
195 
196  $sth = db_query($sql,$dbh);
197  list ($rt,$img,$ckhexkey,$ckorgid,$ckurl)=db_fetch_array($sth,0);
198 
199  $sql = "select trim(micraccount) as micr,
200  trim(checknumber) as check,
201  trim(sortkey) as sk,
202  h.amount,
203  to_char(date,'mm/dd/yyyy') as date
204  from ${iCu}accounthistory h join ${iCu}accountbalance b on
205  (h.accountnumber = b.accountnumber and h.accounttype=b.accounttype
206  and h.certnumber = b.certnumber) where h.accountnumber='$iCn'
207  and h.accounttype='$iAt' and h.certnumber='$iCt' and
208  h.tracenumber = '$iTrace';";
209 
210  $sth = db_query($sql,$dbh);
211  list ($micr,$check,$sk,$amount,$date)=db_fetch_array($sth,0);
212  $amount=sprintf("%.2f",abs($amount));
213 
214  # override micr and rt if needed
215  # clear the 'micr overridden' flag
216  $ovmicr = 0;
217  $sql = "select trim(rt), trim(micraccount)
218  from cuovermicr where cu='$iCu' and accountnumber='$iCn'
219  and accounttype='$iAt' and startcheck <= " . intval($check) .
220  " order by startcheck desc limit 1";
221  $sth = db_query($sql,$dbh);
222 
223  if (db_num_rows($sth) == 1 ) {
224  # we got a hit, override the micr and rt
225  # set a 'micr overridden' flag so we don't discard the changes later
226  # (ISUCU / Scenic Falls)
227  list($rt, $micr) = db_fetch_array($sth,0);
228  $ovmicr = 1;
229  }
230  # HB_ENV['Fset3'] is set from member banking, but not from admin
231  # presumably admin folks would type correct info, not rely on override?
232  if ($HB_ENV['Fset3'] & GetFlagsetValue('CU3_SORTKEY_MICR')) {
233  # now override date / micr from history record if sortkey contains a comma
234  if (preg_match('/,/',$sk)) {
235  list($date36,$micr36) = explode(',',trim($sk),2);
236  $date=base_convert("$date36",36,10);
237  # base convert loses leading zeros, so put 'em back
238  $date = substr("000000$date",-6,6);
239 
240  # mmddyy to mm/dd/yyyy
241  $date = substr($date,0,2) . "/" . substr($date,2,2) . "/20" . substr($date,4,2);
242  $micr=base_convert("$micr36",36,10);
243  }
244  }
245  if ("$sk" == 'ECHECK' ) {
246  NoImage("This is an electronic check. An online image is not available. Please contact the Credit Union if you need a copy of the check for a dispute. ", $adm);
247  exit;
248  }
249 }
250 
251 header("Expires: Sat 20 May 1995 03:32:38 GMT");
252 header("Pragma: no-cache");
253 header("Cache-Control: no-cache, must-revalidate");
254 
255 $CKSIDE = (trim($CKSIDE) == "" ? "F" : trim($CKSIDE));
256 
257 /*
258  * Sometimes we need to adjust the vendor &/or credentials when they have
259  * switched to a new service or data is presented in an odd way
260  * Here are some examples of how to handle that
261  *
262 if ($Cu == "WVANGFCU") {
263 # WVANGFCU will convert from PALMETTO to VOLCORP effective 04/01/2014
264 
265  $ymd = ( substr($date, 6, 4) . substr($date, 0, 2) . substr($date, 3, 2));
266  if ($ymd < '20140401') {
267  $img = 'PALMETTO';
268  $ckhexkey = '80e07c88ef3eee2344abebf882332485';
269  }
270 }
271  */
272 if ($Cu == "COFCU") {
273 # COFCU converted from FIS_IMGCTR to CATALYST 11/13/18. Old images are expected
274 # to be ported to Catalyst, but that hasn't happened yet
275 
276  $ymd = ( substr($date, 6, 4) . substr($date, 0, 2) . substr($date, 3, 2));
277  if ($ymd < '20181113') {
278  NoImage("Images prior to November 13, 2018 are not available. Please contact credit union for assistance.");
279  exit;
280  }
281 }
282 
283 if ($Cu == "MISSFCU") {
284 # MISSFCU will convert from CORPAM to SYNERGENT effective 05/22/2017
285 
286  $ymd = ( substr($date, 6, 4) . substr($date, 0, 2) . substr($date, 3, 2));
287  if ($ymd < '20170522') {
288  $img = 'CORPAM';
289  $ckhexkey = '60e07c67ef3eee2744abebf562332464';
290  }
291 }
292 
293 if ($Cu == 'ISUCU') {
294  if (trim($sortkey) != '') {
295  # checks clearing under PTFCU rt# will have alternate micr in sortkey
296  # and will get images from WESCORP interface
297  $micr = "$sortkey";
298  $rt = "324173697";
299  $img = 'WESCORP';
300 } elseif (strlen($iCn) == 8 && substr($iCn,0,2) == '75') {
301  if ($ovmicr != 1) {
302  # Scenic Falls member
303  $micr = substr($iCn,2);
304 # $rt = '324173150';
305  }
306  } else {
307  # always pad to 12 char beginning with 7300000 for isucu retrieval from catalyst
308  if (strlen(trim($micr)) < 12 ) {
309  $micr = "73" . substr("0000000000" . trim($micr), -10, 10);
310  }
311  }
312 }
313 /*
314  *
315  * Sometimes the cu doesn't process the file right or can't post on a
316  * particular day and we need to block requests with a particular date
317  * Here is an example
318 if ($Cu == "HUNTFCU") {
319 
320 # HUNTFCU switched to VOLCORP w/31 days history. Older checks not available
321 
322  $ymd = ( substr($date, 6, 4) . substr($date, 0, 2) . substr($date, 3, 2));
323  if ($ymd < '20130415') {
324  NoImage("Online images are not available for checks clearing prior to 04/15/2013.<br>Please contact the credit union for assistance.");
325  exit;
326  }
327 }
328 */
329 
330 $trusted = cutrusted_read($dbh, array('Cu' => $iCu, 'trustedid' => 'HcuCheckImages'));
331 if ($trusted['status']['Response'] == 'false') {
332  NoImage("Feature not set up correctly", $adm);
333  exit;
334 }
335 
336 /**
337  * The trusted detail could be coming from the
338  * master record which will cause a warning that
339  * "data" is undefined.
340  *
341  * This key is undefined because the cutm_readdflt
342  * function in cutrusted.i on line 394 uses empty()
343  * to determine if the hcuLogging value exists.
344  *
345  * If the hcuLogging value exists, it will always be 0
346  * in the master record which is also considered empty
347  * causing the "data" key/value not to be created.
348  */
349 $parms = $trusted["data"];
350 $loggingFlag = trim($parms["hcuLogging"]);
351 
352 if (strlen($loggingFlag) > 0) {
353  $enable = $loggingFlag == -1;
354 
355  if (!$enable) {
356  $loggingFlag = str_replace(" ", "", $loggingFlag);
357  $testArray = explode(",", $loggingFlag);
358  $enable = in_array($iCn, $testArray);
359  }
360 
361  if ($enable) {
362 
363  // these are used inside the plugin to test if logging and info to log.
364  $parms["logging"] = "enabled";
365  $parms["environment"] = array("Cu" => $iCu, // credit union
366  "memberId" => $iCn, // member id
367  "SSOVendor" => $img, // image vendor
368  "userIP" => $_SERVER['REMOTE_ADDR'], // user's ip address
369  "dbConn" => $dbh); // database connection
370  }
371 }
372 
373 switch ($img) {
374  case 'WESCORP':
375  case 'MAC':
376  case 'MACIMGONLY':
377  case 'DEMO':
378  case 'SUNCORP':
379  # don't need anything from the database -- nothing there we use
380  break;
381 
382  case 'ALLOYA':
383  case 'FEDIMAGE':
384  case 'CATALYST':
385  case 'SECORP':
386  case 'CORP1':
387  case 'PALMETTO':
388  case 'VOLCORP':
389  case 'CORPAM':
390  case 'MISSOURI':
391  case 'CSI':
392  case 'FISERV':
393  case 'EASCORP':
394  case 'MNIPC':
395  case 'MVI':
396  case 'FIS_IMGCTR':
397  case 'IMAGEPOINT':
398  case 'SYNERGENT':
399  default:
400  # these require monitor values - make sure we have something
401  if ("${ckhexkey}${ckorgid}${ckurl}" == "") {
402  # error feature not set
403  NoImage("Invalid Request (feature parameters not set)", $adm);
404  exit;
405  }
406 }
407 
408 function NoImage($whynot, $adm) {
409 # re-write this to return error structure?
410  global $MC;
411 
412  print <<< EOF
413  <?xml version="1.0"?><!DOCTYPE html>
414  <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
415  <head>
416  <title>{$MC->msg('Cleared Check Detail')}</title>
417  <meta name="robots" content="noindex,nofollow" />
418  <meta http-equiv="X-UA-Compatible" content="IE=8" />
419 EOF;
420 
421  // no branding, yes grid, default Kendo, no home banking styling
422  if ($adm != "1") { setIncludeFiles( FALSE, TRUE, "default", FALSE ); }
423 
424  print <<< EOF
425  <script language=\"JavaScript\"><!--
426  if (window.focus)
427  {
428  window.focus();
429  }
430  if (window.moveTo)
431  {
432  window.moveTo(0,0);
433  }
434 
435  if (document.all)
436  {
437  top.window.resizeTo((screen.availWidth * .85),(screen.availHeight * .85));
438  }
439  else if (document.layers||document.getElementById)
440  {
441  if (top.window.outerHeight<screen.availHeight||top.window.outerWidth<screen.availWidth)
442  {
443  top.window.outerHeight = (screen.availHeight * .85);
444  top.window.outerWidth = (screen.availWidth * .85);
445  }
446  }
447 //--></script>
448  </head>
449  <body>
450 EOF;
451 
452  print <<< ERRORMSG
453  <div style='text-align:center;'>
454  <div class="k-block k-error-colored">
455  <div class="k-header k-error-colored">{$MC->msg('Cleared Check Detail')}</div>
456  <div class="container_12" style='padding: 5px;'>
457  <div class="grid_12"></div>
458  <br>
459  <div class="clear"></div>
460  <div class="grid_12">{$MC->msg('CLEARED CHECK')}</div>
461  <div class="clear"></div>
462  <br>
463  <div class="grid_12">{$whynot}</div>
464  <div class="clear"></div>
465  <br>
466  </div>
467  </div>
468 ERRORMSG;
469 }
470 
471 # set default height and width for image
472 $iheight='198';
473 $iwidth='440';
474 
475 switch ($img) {
476  case 'FIS_IMGCTR':
477 
478  $iheight = '283';
479  $iwidth = '620';
480  $ymd = ( substr($date, 6, 4) . substr($date, 0, 2) . substr($date, 3, 2));
481  $view = strtolower($CKSIDE);
482  $server="https://netimagelr5.fidelityifs.com/imgreq/imgreqis.dll?";
483  $server = $ckurl;
484  $src = "fn=ce&id=${ckorgid}&acct=${micr}&check=${check}&amt=${amount}&side=${view}&date=${ymd}";
485  $front = RawImage($img, $server, $src, $Cu);
486  break;
487 
488  case 'SYNERGENT':
489  $iheight='285';
490  $iwidth='621';
491 
492  if ("$micr"=="") {
493  NoImage("Your account is not set up to view check images. (No MICR)<br>Please contact the credit union for assistance.");
494  exit;
495  }
496 
497  $ymd = ( substr($date,6,4) . substr($date,0,2) . substr($date,3,2));
498  $view = strtolower($CKSIDE);
499 // $server = "https://eresearch.synergentcorp.com/NetHomebanking/vsoft.dll";
500  $server = $ckurl;
501  $amt = str_replace(".", "", $amount);
502  $src = "?fn=ci&id=$ckorgid&acct=${micr}&check=$check&date=$ymd&side=$view&amt=$amt&index=1";
503  $front = RawImage($img, $server, $src, $Cu);
504 
505  break;
506 
507  case 'MVI':
508  $fb = (trim($CKSIDE) == "F" ? "1" : "2");
509  $mvi_query = gmdate('Y-m-d H:i:s') . ",Checks,$micr,$check,$date,$date,$fb";
510 
511  // ENCRYPTION with openssl
512  // The MCRYPT based encryption is still available as encrypt_mvi_mcrypt in
513  // SSOEncryption.i script if for some reason we want to go back to mcrypt
514  // based encryption
515  $mvi_data = encrypt_mvi_openssl($mvi_query, $ckhexkey);
516 
517  $front = "$ckurl?contenttype=jpg&data=$mvi_data";
518  $front = RawImage($img, '', $front, $Cu);
519 
520  break;
521 
522  case 'CATALYST':
523  case 'SWCORP':
524  $iheight = '281';
525  $iwidth = '625';
526  $key = "";
527  for ($i = 0; $i < strlen($ckhexkey); $i+=2) {
528  $key .= chr(hexdec(substr($ckhexkey, $i, 2)));
529  }
530  /*
531  * Simplot has 12 digit micr printed on check
532  * but format inherited from old Western Bridge (Wescorp)
533  * only uses last 6.
534  */
535 // if ($Cu == 'SCU') { $micr = substr($micr,-6,6); } # disabled 12/29/16 MH -
536 // # no images with this on
537 
538  if (($Cu == 'SPCTFCU' || $Cu == 'SNOCOPE') && "$sk" > '') {
539  $tn = $sk;
540  $urlacct = '';
541  $text = "${tn}${amount}${check}${date}${rt}${ckorgid}";
542  } else {
543  $tn = 0;
544  $urlacct = "Account=$micr&";
545  $text = "${micr}${amount}${check}${date}${rt}${ckorgid}";
546  }
547 
548  $mac = hash_hmac('MD5', $text, $key);
549 
550  $front = "https://image.swcorp.org/cgi-bin/$ckurl?${urlacct}Amount=$amount&Serial=$check&Date=$date&CUID=$rt&RQSTRID=$ckorgid&Sequence=$tn&ImageFB=$CKSIDE&MAC=$mac";
551  $front = RawImage($img, '', $front, $Cu);
552  break;
553 
554  case 'SECORP':
555  $iheight = '280';
556  $iwidth = '620';
557 
558  $key = "";
559  for ($i = 0; $i < strlen($ckhexkey); $i+=2) {
560  $key .= chr(hexdec(substr($ckhexkey, $i, 2)));
561  }
562 
563  if ("$micr" == "") {
564  NoImage("Your account is not set up to view check images. (No MICR)<br>Please contact the credit union for assistance.");
565  exit;
566  }
567 
568  $amt = str_replace(".", "", $amount);
569  $text = "${micr}${amt}${check}${date}${rt}";
570  $mac = hash_hmac('MD5', $text, $key);
571 
572  if (!empty($ckurl)) {
573  $front = "{$ckurl}?RT=$rt&PDATE=$date&ACCT=$micr&AMT=$amt&CKNUM=$check&F_B=$CKSIDE&MAC=$mac";
574  } else {
575  #$front = "https://www.secorp.org/homebanking/hbimage.asp?RT=$rt&PDATE=$date&ACCT=$micr&AMT=$amt&CKNUM=$check&F_B=$CKSIDE&MAC=$mac";
576  $front = "https://ww70.corpone.org/homebanking/hbimage.asp?RT=$rt&PDATE=$date&ACCT=$micr&AMT=$amt&CKNUM=$check&F_B=$CKSIDE&MAC=$mac";
577  # changed 4/8/2019. DeltaCU appears to work well; VRCU works when a correct micr is present, but it isn't always
578  # on April 1 2019 change URL to https://ww70.corpone.org/homebanking/hbimage.asp and update DELTACU and VRCU to NOT override the default URL
579  #
580  # Following URL is apparently from an old change that didn't work -- left it here so we don't lose the history
581  #$front = "https://members.corpone.org/homebanking/hbimage.asp?RT=$rt&PDATE=$date&ACCT=$micr&AMT=$amt&CKNUM=$check&F_B=$CKSIDE&MAC=$mac";
582  }
583  $front = RawImage($img, '', $front, $Cu);
584 
585  break;
586 
587  case 'PALMETTO':
588 #
589 # Date is required
590 #
591  switch ($Cu) {
592  case 'WVANGFCU':
593  $ymd = ( substr($date, 6, 4) . substr($date, 0, 2) . substr($date, 3, 2));
594  if ($ymd < '20100702') {
595  NoImage("Images are not available for checks clearing prior to July 2, 2010<br>Please contact the credit union for assistance.");
596  exit;
597  }
598  break;
599  case "TRIAG":
600  if (substr($micr, 0, 4) != '2190') {
601  $micr = '2190' . substr("0000000000000$micr", -9, 9);
602  }
603  break;
604  case "FLCCU":
605  case "FRFCU":
606  $dstamp = strtotime("$date");
607  $fiveback = date("m/d/Y", $dstamp - (86400 * 5));
608  $date = "{$fiveback}::{$date}";
609  break;
610  }
611 
612  $key = "";
613  for ($i = 0; $i < strlen($ckhexkey); $i+=2) {
614  $key .= chr(hexdec(substr($ckhexkey, $i, 2)));
615  }
616 
617  $text = "${micr}${amount}${check}${date}${rt}";
618  $mac = hash_hmac('MD5', $text, $key);
619 
620  $front = "https://hb.creditunionimages.com/homebanking/hbimage.asp?RT=$rt&PDATE=$date&ACCT=$micr&AMT=$amount&CKNUM=$check&F_B=$CKSIDE&MAC=$mac";
621  $front = RawImage($img, '', $front, $Cu);
622  break;
623 
624  case 'VOLCORP':
625  $iheight = '280';
626  $iwidth = '620';
627 
628  $qdate = $date;
629 
630  switch ($Cu) {
631  case 'CURC':
632  $ymd = ( substr($date, 6, 4) . substr($date, 0, 2) . substr($date, 3, 2));
633  if ($ymd < '20100614') {
634  NoImage("Images are not available for checks clearing prior to June 14, 2010<br>Please contact the credit union for assistance.");
635  exit;
636  }
637  break;
638  case 'MIDTNFCU':
639  # Middle Tennessee is posting a day late, so adjust
640  # but only if this request is not from the admin side
641  if ($inc_adm == "") {
642  $ymd = BumpDate($date);
643  $qdate = substr($ymd,4,2) . "/" . substr($ymd,6,2) . "/" . substr($ymd,0,4);
644  }
645  break;
646  }
647 
648 # 8/8/11 don't let request go through if no micr -- might show check from wrong accounts
649  if (trim($micr) == '') {
650  NoImage("Your account is not set up correctly to view images (missing micr).<br>Please contact the credit union for assistance.");
651  exit;
652  }
653  if (($Cu == 'HSCU') && (substr($micr, 0, 7) != '7106300')) {
654  $micr = "7106300$micr";
655  }
656 
657  $key = "";
658  for ($i = 0; $i < strlen($ckhexkey); $i+=2) {
659  $key .= chr(hexdec(substr($ckhexkey, $i, 2)));
660  }
661 
662 # VOLCORP is apparently treating RT# as numeric, not string, so
663 # leading zero on our side disappears on their side and causes hash
664 # mismatch ('Authentication Error'). So we'll play nice and drop the
665 # zero here. VOLCORP is working on an upgrade that will fix this problem.
666 
667  $rt = ltrim($rt, '0');
668 
669  $amt = str_replace(".", "", $amount);
670  $text = "${micr}${amt}${check}${qdate}${rt}";
671  $mac = hash_hmac('MD5', $text, $key);
672 
673 # $front = "https://www.volcorp.org/homebanking/hbimage.asp?RT=$rt&PDATE=$qdate&ACCT=$micr&AMT=$amt&CKNUM=$check&F_B=$CKSIDE&MAC=$mac";
674 # Volcorp redesigned website; url (hostname) changes as below
675  $front = "https://eservices.volcorp.org/homebanking/hbimage.asp?RT=$rt&PDATE=$qdate&ACCT=$micr&AMT=$amt&CKNUM=$check&F_B=$CKSIDE&MAC=$mac";
676  $front = RawImage($img, '', $front, $Cu);
677  break;
678 
679  case 'CORPAM':
680 
681  if ($Cu == 'SONOMA') {
682  $ymd = ( substr($date, 6, 4) . substr($date, 0, 2) . substr($date, 3, 2));
683 
684  if ($ymd < '20140616') {
685  NoImage("Images are not available online for checks clearing prior to June 16, 2014<br>Please contact Sonoma Federal Credit Union at 707 527-6216 for assistance.");
686  exit;
687  }
688  # $ovmicr set when admin micr override is used
689  # don't change the micr again if it is already overridden
690  if ($ovmicr != 1) {
691  if (substr($micr, 0, 8) != '82600000' && $micr <> '100108') {
692  $micr = substr("82600000", 0, 14 - strlen($micr)) . $micr;
693  }
694  }
695  }
696 
697  $key = "";
698  for ($i = 0; $i < strlen($ckhexkey); $i+=2) {
699  $key .= chr(hexdec(substr($ckhexkey, $i, 2)));
700  }
701 
702  $amt = str_replace(".", "", $amount);
703  $text = "${micr}${amt}${check}${date}${rt}";
704  $mac = hash_hmac('MD5', $text, $key);
705 
706  $front = "https://images.corpam.org/homebanking/hbimage.asp?RT=$rt&PDATE=$date&ACCT=$micr&AMT=$amt&CKNUM=$check&F_B=$CKSIDE&MAC=$mac";
707  $front = RawImage($img, '', $front, $Cu);
708  break;
709 
710  case 'WESCORP':
711  $iheight = '300';
712  $iwidth = '629';
713  $idate = "";
714 
715  if ($Cu == 'ALCU' && "$sk" == 'ECHECK') {
716  NoImage("This is an electronic check. An online image is not available. Please contact the Credit Union if you need a copy of the check for a dispute. ");
717  exit;
718  }
719  if (($Cu == 'ISUCU') && (trim($sk) != '')) {
720  $micr = "$sk";
721  $rt = "324173697";
722  }
723 
724  if (($Cu == 'PRRFCU') && (substr($micr, 0, 2) != '79')) {
725  $micr = "79$micr";
726  }
727  $server="https://image.wescorp.org/scripts/afs/afswebapi/afswebapi.dll?";
728  $src = "StreamImage&CUID=$rt&Account=${micr}&Serial=$check&Amount=${amount}&ImageFB=$CKSIDE$idate";
729  $front = RawImage($img, $server, $src, $Cu);
730 
731  break;
732 
733  case 'MAC':
734  $ymd = ( substr($date, 6, 4) . substr($date, 0, 2) . substr($date, 3, 2));
735  if ($Cu == "LEFCU") {
736  if ($ymd > '20111130' && $ymd < '20111213' && $inc_adm == "") {
737 
738  # L'Oreal switched to MidAtlantic Dec 1, but posted on wrong day until 12/14
739  # so for those dates back up 1 business day -- but only if not an adm request
740 
741  $dstamp = strtotime("$date");
742  $wday = date("w", $dstamp); # day of week 0=Sunday
743  switch ($wday) {
744  case 1: # Monday, back up to Friday
745  $ymd = date("Ymd", $dstamp - (86400 * 3));
746  break;
747  default: # back up one day
748  $ymd = date("Ymd", $dstamp - 86400);
749  break;
750  }
751  }
752  }
753 #
754  switch ($Cu) {
755  case 'FCFCU':
756  if ((substr($micr, 0, 3) != '013')) {
757  $micr = '013' . substr($micr, -7, 7);
758  }
759  $tn = 0;
760  break;
761  default:
762  $tn = 0;
763  }
764  $ID = hash('MD5', ($micr . "DMS20070314" . $rt . $tn . $ymd . $amount . $check));
765  $filename = "https://images.midatlanticcorporate.org/image/checkimage_w.asp?aba=$rt&accountnumber=${micr}&amount=$amount&date=$ymd&serialnumber=$check&frontback=ON&tracernumber=$tn&id=$ID";
766 
767  if (HCU_array_key_value("logging", $parms) == "enabled") {
768  $logParms = $parms["environment"]; // get the environment info passed in
769  $logParms["token"] = ''; // the id used across all communications in session
770  $logParms["txnId"] = time(); // the id for this transaction
771  $logParms["logPoint"] = "Mac CK"; // this action in a readable form
772  $logParms["request"] = "ID: $ID \n$filename"; // the request
773  $logParms["reply"] = ""; // the response
774  LogSSOActivity($logParms);
775  }
776 
777  header("Location: $filename");
778  print $MC->msg("Loading Data");
779  exit;
780  break;
781 
782  case 'MACIMGONLY':
783  $ymd = ( substr($date, 6, 4) . substr($date, 0, 2) . substr($date, 3, 2));
784  switch ($Cu) {
785  case 'FCFCU':
786  if ((substr($micr, 0, 3) != '013')) {
787  $micr = '013' . substr($micr, -7, 7);
788  }
789  $tn = 0;
790  break;
791  default:
792  $tn = 0;
793  }
794  $ID = hash('MD5', ($micr . "DMS20070314" . $rt . $tn . $ymd . $amount . $check));
795  $ImageFB = ($CKSIDE == 'B' ? 'ON' : 'OFF');
796  $server = "https://images.midatlanticcorporate.org/image/checkimage.asp?";
797  $src = "aba=$rt&accountnumber=${micr}&amount=$amount&date=$ymd&serialnumber=$check&frontback=$ImageFB&tracernumber=$tn&id=$ID";
798  $front = RawImage($img, $server, $src, $Cu);
799 
800  break;
801 
802  case 'CORP1':
803  $iheight = '246';
804  $iwidth = '550';
805 
806  $server = "https://ww10.corpone.org/showdraft/DIshowdraft.asp?";
807  $src = "rt=$rt&rs=$ckhexkey&ac=$micr&sn=$check&am=$amount&dc=$date&face=$CKSIDE";
808  $front = RawImage($img, $server, $src, $Cu);
809 
810  break;
811 
812  case 'MNIPC':
813  # 7/17/14 add ArchiveConfig to url string.
814  // (Using ckurl because MNIPC sets longer value than will fit in the ckorgid or ckhexkey column)
815  $server = "https://Ryan.mnipc.com/scripts/afs/afswebapi/afswebapi.dll?StreamImage?";
816  $src = "RT=$rt&Account=${micr}&Serial=$check&Amount=$amount&ImageFB=$CKSIDE&ArchiveConfig=$ckurl";
817  $front = RawImage($img, $server, $src, $Cu);
818 
819  break;
820 
821  case 'ALLOYA':
822  # this is the new interface from Alloya in partnership with Catalyst
823  # 12/19/16 older Alloya interface renamed ALLOYA_VS
824  # copied Catalyst interface & modified URL
825  # also dropped conditional code to use $tn trace number instead of micr account
826  # see CATALYST if you need that back
827  # also copied the 'bail if no micr' block from older ALLOYA interface... kinda like it
828  # but it won't work if you re-engage the trace number block
829 
830  if ("$micr" == "") {
831  NoImage("Your account is not set up to view check images. (No MICR)<br>Please contact the credit union for assistance.");
832  exit;
833  }
834  $iheight = '281';
835  $iwidth = '625';
836  $key = "";
837  for ($i = 0; $i < strlen($ckhexkey); $i+=2) {
838  $key .= chr(hexdec(substr($ckhexkey, $i, 2)));
839  }
840  $ymd = ( substr($date, 6, 4) . substr($date, 0, 2) . substr($date, 3, 2));
841  # Alloya interface drops leading zero from rt#
842  $rt = ltrim($rt, '0');
843  $text = "${micr}${amount}${check}${ymd}${rt}${ckorgid}";
844  $mac = hash_hmac('MD5', $text, $key);
845 
846  $front = "https://imageview.alloyacorp.org/NetHomeBanking/$ckurl?Account=$micr&Amount=$amount&Serial=$check&Date=$ymd&CUID=$rt&RQSTRID=$ckorgid&ImageFB=$CKSIDE&MAC=$mac";
847  $front = RawImage($img, '', $front, $Cu);
848 
849  break;
850 
851  case 'IMAGEPOINT':
852  $iheight = '285';
853  $iwidth = '621';
854 
855  if ("$micr" == "") {
856  NoImage("Your account is not set up to view check images. (No MICR)<br>Please contact the credit union for assistance.");
857  exit;
858  }
859 
860  $ymd = ( substr($date, 6, 4) . substr($date, 0, 2) . substr($date, 3, 2));
861  $amt = str_replace(".", "", $amount); # decimal point implied
862 
863 // $server = "https://iparchive.lonestarcu.org/ipfawebapi/query.aspx?";
864  $server = $ckurl;
865  $src = "fn=iteminq&id=$ckorgid&acct=${micr}&check=$check&date=$ymd&side=$CKSIDE&amt=$amt&index=1";
866  $front = RawImage($img, $server, $src, $Cu);
867  break;
868 
869  case 'DEMO':
870  $front = democheck($CKSIDE);
871  break;
872 
873  case 'SUNCORP':
874  $iheight = '297';
875  $iwidth = '660';
876  /*
877  * WEBERCU (Wasatch Peaks) merged w/Alliance CU -- use alternate MICR if it is provided
878  * to get check images for formerly-Alliance members
879  */
880  if (($Cu == 'WEBERCU') && (trim($sk) != '')) {
881  $micr = "$sk";
882  $rt = "324377590";
883  }
884  $server = "https://imageconnect.suncorp.coop/scripts/afs/afswebapi/afswebapi.dll?StreamImage?";
885  $src = "TR=$rt&Account=${micr}&Serial=$check&Amount=${amount}&ImageFB=$CKSIDE";
886  $front = RawImage($img, $server, $src, $Cu);
887 
888  break;
889 
890  case 'MISSOURI':
891  if ($Cu == "KRAFTCOR") {
892 # KRAFTCOR switched to MISSOURI. Older checks not available
893 
894  $ymd = ( substr($date, 6, 4) . substr($date, 0, 2) . substr($date, 3, 2));
895  if ($ymd < '20151201') {
896  NoImage("Online images are not available for checks clearing prior to 12/01/2015.<br>Please contact the credit union for assistance.");
897  exit;
898  }
899  }
900  $server = "https://www.lipcgatekeeper.org:2000";
901  $front = "$ckurl?Acct=$micr&Cnum=$check&Amt=$amount&Img=$CKSIDE";
902 
903  $miss = "$server$front";
904  $fd = fopen($miss, 'rb');
905  if ($fd) {
906  $fx = fgets($fd, 4096);
907  if (preg_match("/NO MATCH FOUND/", $fx) || preg_match("/INVALID REQUEST/", $fx)) {
908  $front = "Check Image Not Found";
909  } else {
910  $fx = str_replace("<IMG SRC=\"", "", $fx);
911  $fx = str_replace("\">", "", $fx);
912  $front = RawImage($img, '', $fx, $Cu);
913 
914  }
915  } else {
916  $front = "Check Image Not Found";
917  }
918 
919  break;
920 
921  case 'EASCORP':
922 #
923 # 3/9/10 Eascorp changing to unique requestor id and key for each cu
924 # requestor id is routing# dash DMS
925 # secret key will come from monitor Check Security Key
926 
927  $key = "";
928  for ($i = 0; $i < strlen($ckhexkey); $i+=2) {
929  $key .= chr(hexdec(substr($ckhexkey, $i, 2)));
930  }
931 
932  $session = substr('000000000' . strval(rand(1, 999999999)), -9);
933  if ($iCu != 'STCU') {
934  $micr = substr('0000000000' . $micr, -10);
935  }
936  $timestamp = gmmktime();
937 
938  $text = "${rt}-DMS${session}${timestamp}${rt}${iCn}${micr}";
939  $mac = hash_hmac('MD5', $text, $key);
940  $src = "https://www.member-data.com/hb/hb_ckcp.ashx";
941 
942  $dxml = "<?xml version=\"1.0\" encoding=\"utf-8\"?>
943  <request>
944  <requestor>${rt}-DMS</requestor>
945  <session>$session</session>
946  <timestamp>$timestamp</timestamp>
947  <routing>$rt</routing>
948  <member>$iCn</member>
949  <ck-account>$micr</ck-account>
950  <ck-date>$date</ck-date>
951  <ck-ck-number>$check</ck-ck-number>
952  <ck-amount>$amount</ck-amount>
953  <MAC>$mac</MAC>
954  </request>";
955 
956 
957 #$cmd="/usr/bin/curl --show-error --dump-header '/tmp/xmlhead' --include --data-binary '$dxml' -H 'Content-Type: text/xml' $src";
958 
959  $cmd = "/usr/bin/curl --silent --data-binary '$dxml' -H 'Content-Type: text/xml' $src";
960 
961  $fd = popen("$cmd", "r");
962 
963  $response = "";
964  if ($fd) {
965  do {
966  $data = @fread($fd, 8192);
967  if (strlen($data) == 0) {
968  break;
969  }
970  $response .= $data;
971  } while (true);
972 
973  pclose($fd);
974  }
975 
976  $nocheck = 0;
977  if (!preg_match("#<URL>#s", $response)) {
978  $nocheck = 1;
979  }
980 
981  $url = preg_replace("#</URL>.*$#s", "", $response, -1);
982  $url = preg_replace("#.*<URL>#s", "", $url, -1);
983  $src = "https://$url";
984 
985  if (HCU_array_key_value("logging", $parms) == "enabled") {
986  $logParms = $parms["environment"]; // get the environment info passed in
987  $logParms["token"] = ''; // the id used across all communications in session
988  $logParms["txnId"] = time(); // the id for this transaction
989  $logParms["logPoint"] = "Eascorp CK"; // this action in a readable form
990  $logParms["request"] = $cmd; // the request
991  $logParms["reply"] = "URL $src \n$response"; // the response
992  LogSSOActivity($logParms);
993  }
994 
995  if (!$nocheck) {
996  header("Location: $src");
997  print $MC->msg("Loading Data");
998  } else {
999  print $MC->msg("Check Image Not Found");
1000  }
1001  exit;
1002  break;
1003 
1004  case 'CSI':
1005 #
1006 # Date is required and must match with corporate clearing date
1007 #
1008  $key = "";
1009  for ($i = 0; $i < strlen($ckhexkey); $i+=2) {
1010  $key .= chr(hexdec(substr($ckhexkey, $i, 2)));
1011  }
1012 
1013  $text = "${micr}${amount}${check}${date}${rt}";
1014  $mac = hash_hmac('MD5', $text, $key);
1015 
1016  $front = "https://hb.csiimage.com/homebanking/hbimage.asp?RT=$rt&PDATE=$date&ACCT=$micr&AMT=$amount&CKNUM=$check&F_B=$CKSIDE&MAC=$mac";
1017  $front = RawImage($img, '', $front, $Cu);
1018  break;
1019 
1020  case 'FEDIMAGE':
1021 
1022  switch ($Cu) {
1023  case "SFEFCU":
1024  $ymd = ( substr($date, 6, 4) . substr($date, 0, 2) . substr($date, 3, 2));
1025  if ($ymd < '20101201') {
1026  NoImage("Images are not available for checks clearing prior to December 1, 2010<br>Please contact the credit union for assistance.");
1027  exit;
1028  }
1029  $bytrace = 0;
1030  break;
1031 // case "FIRSTLIB":
1032 // # treat micrs beginning with 11800 as commercial accounts, passing
1033 // // check number in XML query as 'Aux On Us' instead of 'Check Number'
1034 // // waiting for client to confirm this is dependable method of identifying
1035 // // commercial accounts before committing / deploying MHall
1036 // if (substr($micr,0,5) == '11800') {
1037 // $bytrace=2;
1038 // } else {
1039 // $bytrace=0;
1040 // }
1041 // break;
1042  default:
1043  $bytrace = 0;
1044  }
1045  # $certfile, $pass, url used to come from FedSpecs.i.
1046  # Moving those things into monitor for easier support
1047  # but note that FedSpecs.i had FQ path for certfile, but monitor entry
1048  # is limited to 32 char & I don't want to mess with it now.
1049  # So assume the location is in cu sslforms directory.
1050  #
1051  # Odyssey uses shared ssl certs directory
1052  # ckhexkey value should start with 'test/certs/cks/' or 'prod/certs/cks/'
1053  # note that ckhexkey value is varchar(50), and the required prefix uses 15
1054  # so... be brief with the cert file names!
1055 
1056  $certSecretId = trim($ckhexkey);
1057 
1058  /**
1059  * Retrieve and decrypt the cert file
1060  */
1061  $certfile = GetAwsCertFile($certSecretId, HOMECU_ENC_CERT_DIR, HOMECU_DOCK_CERT_DIR);
1062 
1063  if ($certfile == '' || !(is_readable($certfile))) {
1064  NoImage("Invalid Request (feature parameters not set)" , $adm);
1065  exit;
1066  }
1067  $pass = $ckorgid;
1068  $server = $ckurl;
1069  # FedImageGL gets the image links & call FedImageSI to get image stream
1070  # so what we get here is data:image/gif followed by encoded image bytes ready to display
1071  $imglist = FedImageGL($Cu, $date, $amount, $check, $rt, $micr, $sk, $bytrace, $certfile, $pass, $server);
1072  $front = $imglist['Front'];
1073  $back = $imglist['Back'];
1074  break;
1075 
1076  case 'FISERV':
1077 #
1078 # by default, the date value passed to Fiserv is the date of the check
1079 # but ICCCU has some special processing because they get the file late
1080 # from Fiserv. See switch by $Cu in FiservImage script
1081 # 2/23/17
1082 # ICCCU went away, now KONECU posts the file late and uses the date adjustment,
1083 # and FiservImage is now a function rather than a separate script.
1084 #
1085  $iheight = '273';
1086  $iwidth = '627';
1087  $server = "https://www.fiservcws.com/ui/wsinterface.asmx";
1088 # $orgid="44444451"; # testing
1089 
1090  switch ($Cu) {
1091  case 'CAOFCU':
1092  $ymd = ( substr($date, 6, 4) . substr($date, 0, 2) . substr($date, 3, 2));
1093  if ($ymd < '20091001') {
1094  NoImage("Online images are not available for checks cleared prior to October 1, 2009.<br><br>&nbsp;Please contact the Credit Union for images of these checks.");
1095  exit;
1096  }
1097  break;
1098  }
1099 
1100  $text = "${Cu}${amount}${check}${micr}${rt}${date}${ckorgid}";
1101  $front = FiservImage($Cu, $CKSIDE, $amount, $check, $micr, $rt, $date, $ckorgid);
1102  break;
1103 }
1104 
1105  print <<< EOF
1106  <?xml version="1.0"?><!DOCTYPE html>
1107  <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
1108  <head>
1109  <title>{$MC->msg('Cleared Check Detail')}</title>
1110  <meta name="robots" content="noindex,nofollow" />
1111  <meta http-equiv="X-UA-Compatible" content="IE=8" />
1112 EOF;
1113 
1114 setIncludeFiles( FALSE, TRUE, "default", FALSE );
1115 
1116 
1117  print <<< EOF
1118  <script language=\"JavaScript\"><!--
1119  if (window.focus)
1120  {
1121  window.focus();
1122  }
1123  if (window.moveTo)
1124  {
1125  window.moveTo(0,0);
1126  }
1127 
1128  if (document.all)
1129  {
1130  top.window.resizeTo((screen.availWidth * .85),(screen.availHeight * .85));
1131  }
1132  else if (document.layers||document.getElementById)
1133  {
1134  if (top.window.outerHeight<screen.availHeight||top.window.outerWidth<screen.availWidth)
1135  {
1136  top.window.outerHeight = (screen.availHeight * .85);
1137  top.window.outerWidth = (screen.availWidth * .85);
1138  }
1139  }
1140 //--></script>
1141  </head>
1142  <body>
1143 EOF;
1144 ?>
1145  <div class="text-center">
1146  <div class="well well-sm col-sm-12 ">
1147  <div class="text-left">
1148  <label><?php echo $MC->msg('Date Cleared') ?>:</label>
1149  <label style="font-weight: normal;"><?php echo $date; ?></label><br>
1150  <label><?php echo $MC->msg('Check Number') ?>:</label>
1151  <label style="font-weight: normal;"><?php echo $check; ?></label><br>
1152  <label><?php echo $MC->msg('Amount') ?>:</label>
1153  <label style="font-weight: normal;"><?php echo $amount; ?>
1154  </div>
1155  <?php
1156  print "<br>";
1157  // Display the front image
1158  if ($front == "Check Image Not Found") {
1159  print $MC->msg('Check Image Not Found') . "<br>";
1160  } else {
1161  print "<img src='$front' height='$iheight' width='$iwidth' alt='" . $MC->msg('Please Wait') . "...' border=1>";
1162  print "<br>";
1163 
1164  /**
1165  * FEDIMAGE is the only vendor that gives front and back
1166  * images on request, display both at the same time and
1167  * skip the View back / front button.
1168  */
1169  if ($img == "FEDIMAGE") {
1170  // Check if back image exists
1171  // Add extra break to get some space beteween images
1172  if ($back != "NO") {
1173  print "<br>";
1174  print "<img src='$back' height='$iheight' width='$iwidth' alt='" . $MC->msg('Please Wait') . "...' border=1>";
1175  }
1176  } else {
1177  if (empty($back)) {
1178  // Show View Back / Front button here for other vendors
1179  $NextCKSIDE = ($CKSIDE == 'F' ? 'B' : 'F');
1180  $view = ($NextCKSIDE == 'F' ? 'Front' : 'Back');
1181  $viewCaption = $MC->msg("View $view");
1182 
1183  print "<br><a id='ckViewBtn' class='k-button' href=\"{$CHK_URL}cu=$Cu&CKITEM=${CKITEM}&CKARCHIVE={$CKARCHIVE}&CKHASH=${CKHASH}" . ($inc_adm ? "&adm=1" : "" ) . "&CKSIDE=$NextCKSIDE\">$viewCaption</a>";
1184  }
1185  }
1186  }
1187  ?>
1188  <br>&nbsp;
1189  </div>
1190  </div>
1191  </div>
1192  </body>
1193 </html>
1194 
1195 <?php
1196 
1197  /**
1198  * democheck Retrieves dummy check image for demo purposes
1199  * @param string $ckside pick 'F'ront or 'B'ack
1200  * @return string base64 encoded image bytes
1201  */
1202  function democheck($ckside) {
1203  $theader = "data:image/jpg";
1204  # using hard-coded path instead of HB_ENV['cloudfrontDomainName']
1205  # because this runs from both banking and admin (HB_ENV undefined in admin)
1206  $imagefile = "https://d1kryjpwpzirc7.cloudfront.net/odyssey/images/demo_chk" . strtolower($ckside) . ".jpg";
1207 
1208  $nctypehead = "data:image/gif";
1209  $nocheck = "https://d1kryjpwpzirc7.cloudfront.net/odyssey/images/nochecksgl.gif";
1210  $headers = get_headers($imagefile,1);
1211  if ( stristr( $headers[0], '200 OK') !== false && stristr( $headers['Content-Type'], 'image') !== false ) {
1212  $imagebytes = file_get_contents($imagefile);
1213  } else {
1214  $imagebytes = file_get_contents($nocheck);
1215  $theader = $nctypehead;
1216  }
1217  return $theader . ';base64,' . base64_encode($imagebytes);
1218  }
1219 
1220  /**
1221  * RawImage Retrieves the raw bytes for an image
1222  * @global array $parms get settings for vendor logging
1223  * @param string $img which image vendor cuadmin.img
1224  * @param string $server host portion of vendor URL
1225  * @param string $src http query portion of vendor URL
1226  * @param string $Cu client code
1227  * @param array $opts loophole for passing additional vendor-specific options
1228  * @return string base64 encoded image bytes
1229  */
1230  function RawImage($img, $server, $src, $Cu, $opts = array() ) {
1231 // accept $opts as a parameter and add to it -
1232 // allow interfaces a loophole for specifying other settings if needed
1233 // used later to set stream options
1234 // ignore errors on the stream operation
1235 // so we can catch them after & still have the content
1236 
1237  $opts['http']['ignore_errors'] = true;
1238 
1239 # set some defaults
1240  # using hard-coded path instead of HB_ENV['cloudfrontDomainName']
1241  # because this runs from both banking and admin (HB_ENV undefined in admin)
1242  $nocheck = "https://d1kryjpwpzirc7.cloudfront.net/odyssey/images/nochecksgl.gif";
1243  $nctypehead = "data:image/gif";
1244 
1245  $curlopts = array(
1246  CURLOPT_RETURNTRANSFER => 1,
1247  CURLOPT_SSL_VERIFYPEER => 0,
1248  CURLOPT_SSL_VERIFYHOST => 0,
1249  CURLOPT_HEADER => FALSE,
1250  CURLOPT_URL => "${server}${src}");
1251 
1252  $ch = curl_init();
1253 //curl_setopt($ch, CURLOPT_VERBOSE, true);
1254 //$verbose = fopen('/tmp/fstrace', 'a+');
1255 //curl_setopt($ch, CURLOPT_STDERR, $verbose);
1256 
1257  curl_setopt_array($ch, $curlopts);
1258 
1259  $respERR = '';
1260  $imagebytes = curl_exec($ch);
1261  $respHTTP = curl_getinfo($ch, CURLINFO_HTTP_CODE);
1262  $respTYPE = curl_getinfo($ch, CURLINFO_CONTENT_TYPE); # gets NULL if no valid Content-Type
1263  $respCURL = curl_errno($ch);
1264 
1265  if ($respCURL) {
1266  # curl error
1267  $respERR = "HCUERROR: Connection Failed cURL $respCURL";
1268  } elseif ($respHTTP > 400 && $respHTTP < 600) {
1269  # HTTP Response 4xx client error or 5xx server error
1270  $respERR = "HCUERROR: Connection Failed HTTP $respHTTP ";
1271  } elseif (!isset($imagebytes) || $imagebytes == '') {
1272  # no response
1273  $respERR = "HCUERROR: Empty Response";
1274  } elseif (is_null($respTYPE) || strtolower(substr($respTYPE, 0, 5)) != 'image') {
1275  # Content-Type header missing or not an image
1276  $respERR = "HCUERROR: Response Not an Image";
1277  } else {
1278  # should be good response
1279  $theader = "data:" . trim($respTYPE);
1280  }
1281 
1282  global $parms;
1283  if (HCU_array_key_value("logging", $parms) == "enabled") {
1284  $logParms = $parms["environment"]; // get the environment info passed in
1285  $logParms["token"] = ''; // the id used across all communications in session
1286  $logParms["txnId"] = time(); // the id for this transaction
1287  $logParms["logPoint"] = "$img RawImage"; // this action in a readable form
1288  $logParms["request"] = "${server}${src}"; // the request
1289  $logParms["reply"] = "$respERR\n"; // the response
1290  if (is_null($respTYPE) || strtolower(substr($respTYPE, 0, 5)) != 'image') {
1291  $logParms["reply"] .= $imagebytes;
1292  } else {
1293  $logParms["reply"] .= "(IMAGE DATA)\n"; // This is a string
1294  }
1295  LogSSOActivity($logParms);
1296  }
1297 
1298  if ($respERR != '') {
1299  $theader = $nctypehead;
1300  $imagebytes = file_get_contents($nocheck);
1301  }
1302 
1303  return $theader . ';base64,' . base64_encode($imagebytes);
1304  }
1305 
1306  /**
1307  * FiservImage builds query and retrieves image from Fiserv
1308  * @global array $parms get settings for vendor logging
1309  * @param string $Cu client cu code cuadmin.cu
1310  * @param string $view pick 'F'ront or 'B'ack image
1311  * @param currency $amount check amount
1312  * @param string $check check number
1313  * @param string $micr member micr
1314  * @param string $rt cu routing / transit cuadmin.rt
1315  * @param string $ckdate check date
1316  * @param string $orgid client orgid issued by Fiserv
1317  * @return string base64 encoded image bytes
1318  */
1319  function FiservImage($Cu, $view, $amount, $check, $micr, $rt, $ckdate, $orgid) {
1320  # only one client (Konecu) on this interface, and none of their images work
1321  # turns out they are posting a day late - use BumpDate to adjust
1322  # 2/15/17 moving on to FedImage
1323 #$front="FiservImage?cu=$Cu&view=$CKSIDE&amount=$amount&check=$check&micr=$micr&rt=$rt&date=$date&orgid=$ckorgid{$inc_adm}&imgkey=$imgkey";
1324 # $prid="Test";
1325 # $prpwd="i+PJQ7Fgn/+/xRqtZm0KBK34PJ0=";
1326  $prid = "HomeCU";
1327  $prpwd = "osSqERHPDtl5w5zsz3UDYl7X8ks=";
1328  $server = "https://www.fiservcws.com/ui/wsinterface.asmx";
1329 
1330  $dstamp = strtotime("$ckdate");
1331 
1332  switch ($Cu) {
1333  case "ICCCU":
1334  case "KONECU":
1335  $ymd = BumpDate($ckdate);
1336  break;
1337  default:
1338  $ymd = date("Ymd", $dstamp);
1339  break;
1340  }
1341 
1342  $datetime = (date("Y-m-d") . "T" . date("H:i:sO"));
1343 
1344  $dxml = '<fiAPI xmlns="http://integration.fiapi.com" ';
1345  $dxml .= 'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ';
1346  $dxml .= 'xmlns:xenc="http://www.w3.org/2001/04/xmlenc#" ';
1347  $dxml .= 'xsi:schemaLocation="http://integration.fiapi.com fiDocumentInquiry.xsd"> ';
1348  $dxml .= '<fiHeader Version="2.0"> ';
1349  $dxml .= '<Service Version="1.0" Name="FiservArchiveAccessAPI"> ';
1350  $dxml .= '<DateTime>' . $datetime . '</DateTime> ';
1351  $dxml .= '<UUID>12345678-1234-1234-1234-123456789012</UUID> ';
1352  $dxml .= '</Service> ';
1353  $dxml .= '<Security> ';
1354  $dxml .= '<AuthenticationMaterial> ';
1355  $dxml .= '<PrincipalPWD>' . $prpwd . '</PrincipalPWD> ';
1356  $dxml .= '</AuthenticationMaterial> ';
1357  $dxml .= '<PrincipalID>' . $prid . '</PrincipalID> ';
1358  $dxml .= '</Security> ';
1359  $dxml .= '<Client Version="1.3"> ';
1360  $dxml .= '<VendorID>Vendor Name</VendorID> ';
1361  $dxml .= '<AppID>CWS</AppID> ';
1362  $dxml .= '<OrgID>' . $orgid . '</OrgID> ';
1363  $dxml .= '<SessionID>88888888-4444-4444-4444-123456789012</SessionID> ';
1364  $dxml .= '</Client> ';
1365  $dxml .= '<DataSource> ';
1366  $dxml .= '<URI /> ';
1367  $dxml .= '</DataSource> ';
1368  $dxml .= '</fiHeader> ';
1369  $dxml .= '<Request TypeOfRequest="DocumentInquiryRq" RequestID="123" Echo="0"> ';
1370  $dxml .= '<Date>' . $ymd . '</Date> ';
1371  $dxml .= '<Class>Check</Class> ';
1372  $dxml .= '<Type>GetImage</Type> ';
1373  $dxml .= '<Condition> ';
1374  $dxml .= '<Detail>ItemSeqNum</Detail> ';
1375  $dxml .= '<Operator>EQ</Operator> ';
1376  $dxml .= '<Value>0</Value> ';
1377  $dxml .= '</Condition> ';
1378  $dxml .= '<Condition> ';
1379  $dxml .= '<Detail>CheckAmt</Detail> ';
1380  $dxml .= '<Operator>EQ</Operator> ';
1381  $dxml .= '<Value>' . $amount . '</Value> ';
1382  $dxml .= '</Condition> ';
1383  $dxml .= '<Condition> ';
1384  $dxml .= '<Detail>TransCode</Detail> ';
1385  $dxml .= '<Operator>EQ</Operator> ';
1386  $dxml .= '<Value>' . $check . '</Value> ';
1387  $dxml .= '</Condition> ';
1388  $dxml .= '<Condition> ';
1389  $dxml .= '<Detail>AccountNum</Detail> ';
1390  $dxml .= '<Operator>EQ</Operator> ';
1391  $dxml .= '<Value>' . $micr . '</Value> ';
1392  $dxml .= '</Condition> ';
1393  $dxml .= '<Condition> ';
1394  $dxml .= '<Detail>TrRoutNum</Detail> ';
1395  $dxml .= '<Operator>EQ</Operator> ';
1396  $dxml .= '<Value>' . $rt . '</Value> ';
1397  $dxml .= '</Condition> ';
1398  $dxml .= '<Condition> ';
1399  $dxml .= '<Detail>SerialNum</Detail> ';
1400  $dxml .= '<Operator>EQ</Operator> ';
1401  $dxml .= '<Value>' . $check . '</Value> ';
1402  $dxml .= '</Condition> ';
1403  $dxml .= '<RequestData ID="1" Name="1" Date="1" Class="1" Type="1"> ';
1404  $dxml .= '<Page View="' . $view . '" Format="gif">1</Page> ';
1405  $dxml .= '</RequestData> ';
1406  $dxml .= '<RequestMetaData /> ';
1407  $dxml .= '</Request> ';
1408  $dxml .= '</fiAPI>';
1409 
1410  $dxml = htmlspecialchars($dxml, ENT_NOQUOTES);
1411 
1412  $os = '<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ';
1413  $os .= 'xmlns:xsd="http://www.w3.org/2001/XMLSchema" ';
1414  $os .= 'xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> ';
1415  $os .= '<soap:Body> ';
1416  $os .= '<SubmitRequest xmlns="urn:Fiserv.CWS"> ';
1417  $os .= '<FiAPIRequest>' . $dxml . '</FiAPIRequest> ';
1418  $os .= '</SubmitRequest> ';
1419  $os .= '</soap:Body> ';
1420  $os .= '</soap:Envelope> ';
1421 
1422  $response = "";
1423  # using hard-coded path instead of HB_ENV['cloudfrontDomainName']
1424  # because this runs from both banking and admin (HB_ENV undefined in admin)
1425  $nocheck = "https://d1kryjpwpzirc7.cloudfront.net/odyssey/images/nochecksgl.gif";
1426  $nctypehead = "data:image/gif";
1427  $front = "Check Image Not Found";
1428 
1429  $cmd = "/usr/bin/curl --silent --data-binary '$os' -H 'Content-Type: text/xml' -H 'SOAPAction: \"urn:Fiserv.CWS/SubmitRequest\"' '$server'";
1430 
1431 # use embedded curl to get results, check errors
1432 
1433  $curlopts = array(
1434  CURLOPT_RETURNTRANSFER => 1,
1435  CURLOPT_SSL_VERIFYPEER => 0,
1436  CURLOPT_SSL_VERIFYHOST => 0,
1437  CURLOPT_HEADER => FALSE,
1438  CURLOPT_POSTFIELDS => $os,
1439  CURLOPT_URL => "$server");
1440  $reqHeaders = array('Content-Type: text/xml', 'SOAPAction: "urn:Fiserv.CWS/SubmitRequest"');
1441 
1442  $ch = curl_init();
1443 //curl_setopt($ch, CURLOPT_VERBOSE, true);
1444 //$verbose = fopen('/tmp/fstrace', 'a+');
1445 //curl_setopt($ch, CURLOPT_STDERR, $verbose);
1446 
1447  curl_setopt_array($ch, $curlopts);
1448  curl_setopt($ch, CURLOPT_HTTPHEADER, $reqHeaders);
1449 
1450  $respERR = '';
1451  $response = curl_exec($ch);
1452  $respHTTP = curl_getinfo($ch, CURLINFO_HTTP_CODE);
1453  $respTYPE = curl_getinfo($ch, CURLINFO_CONTENT_TYPE); # gets NULL if no valid Content-Type
1454  $respCURL = curl_errno($ch);
1455 
1456  if ($respCURL) {
1457  # curl error
1458  $respERR = "HCUERROR: Connection Failed cURL $respCURL";
1459  } elseif ($respHTTP > 400 && $respHTTP < 600) {
1460  # HTTP Response 4xx client error or 5xx server error
1461  $respERR = "HCUERROR: Connection Failed HTTP $respHTTP ";
1462  } elseif (!isset($response) || $response == '') {
1463  # no response
1464  $respERR = "HCUERROR: Empty Response";
1465 // } elseif (is_null($respTYPE) || strtolower(substr($respTYPE,0,5)) != 'image') {
1466 // FiServ returns XML, not just the image
1467 // # Content-Type header missing or not an image
1468 // $respERR = "HCUERROR: Response Not an Image";
1469  }
1470 
1471  if ($respERR == '') {
1472  # set xml to catch errors, and remember the current setting
1473  $xmlerr_setting = libxml_use_internal_errors(true);
1474 
1475  $xml = simplexml_load_string($response);
1476 
1477  # retrieve any errors encountered on the load
1478  $xmlerrors = libxml_get_errors();
1479  # clear the internal buffer
1480  libxml_clear_errors();
1481  # put the setting back to previous state
1482  libxml_use_internal_errors($xmlerr_setting);
1483 
1484  if (!is_object($xml)) {
1485  $respERR = "HCUERROR INVALID XML: ";
1486  # if we need to print ea. error this would do it
1487  # but really just want to know the doc. didn't load
1488 // foreach ($xmlerrors as $error) {
1489 // $respERR .= $error->message;
1490 // }
1491  }
1492 
1493 # look for soap level error
1494  $xml->registerXPathNamespace('s', "http://schemas.xmlsoap.org/soap/envelope/");
1495  $errorresponse = $xml->xpath("//s:Fault");
1496  if (is_array($errorresponse) && count($errorresponse)) {
1497  $respERR = "HCUERROR: " . $errorresponse[0]->faultcode . " " . $errorresponse[0]->faultstring;
1498  } else {
1499 # got this far, guess good document first -
1500  $xml->registerXPathNamespace('chk', 'http://integration.fiapi.com');
1501 # xml always returns an array. But there will only by 1, so use [0]
1502  $respType = $xml->xpath("//chk:Response")[0]['TypeOfResponse'][0];
1503  if ($respType == 'DocumentInquiryRs') {
1504  $image = $xml->xpath("//chk:Page")[0];
1505  $theader = "data:image/" . $image['Format'];
1506  $imagebytes = base64_decode($image->Value);
1507  } elseif ($respType == 'ERROR') {
1508  $respAPI = $xml->xpath("//chk:Status")[0];
1509  $respERR = "HCUERROR: " . $respAPI->StatusCode . " " . $respAPI->Desc;
1510  } else {
1511  $respERR = "HCUERROR: Unexpected XML content";
1512  }
1513  }
1514  }
1515  if ($respERR != '') {
1516  $theader = $nctypehead;
1517  $imagebytes = file_get_contents($nocheck);
1518  }
1519  global $parms;
1520  if (HCU_array_key_value("logging", $parms) == "enabled") {
1521  $logParms = $parms["environment"]; // get the environment info passed in
1522  $logParms["token"] = ''; // the id used across all communications in session
1523  $logParms["txnId"] = time(); // the id for this transaction
1524  $logParms["logPoint"] = "FiServ Image"; // this action in a readable form
1525  $logParms["request"] = "$cmd"; // the request
1526  $logParms["reply"] = "$respERR\n"; // the response
1527  // On successful inquiry of check image, whether or not we get
1528  // a real check image or check image not found the vendor will
1529  // return xml content.
1530 
1531  // We want to log everything but the image data itself, so we
1532  // replace the Page->Value with '(IMAGE DATA)'
1533  // Page:
1534  // Number: page number
1535  // Format: image format -> gif
1536  // View: front or back -> F / B
1537  // Value: image bytes
1538 
1539  // The Page->Value is contained rather deep in the xml structure
1540  // chk:Response->DocumentInquiryRs->Document->Page->Value
1541  if ($respType == "DocumentInquiryRs") {
1542  $xmlPage = $xml->xpath("//chk:Page")[0];
1543  $xmlPage->Value = "(IMAGE DATA)";
1544  $logParms["reply"] .= $xml->asXML();
1545  } else {
1546  // Error, no iamge data. Log response from core
1547  $logParms["reply"] .= $response;
1548  }
1549  LogSSOActivity($logParms);
1550  }
1551 
1552 
1553  return $theader . ';base64,' . base64_encode($imagebytes);
1554  }
1555 
1556 /**
1557  * BumpDate Function to bump a processing date back to the previous work date
1558  * build a list of Federal holidays, and if we landed on a holiday
1559  * back up some more.
1560  * @param string $ckdate date of the check to be considered
1561  * @return string YMD date to be used in image retrieval
1562  */
1563  function BumpDate($ckdate) {
1564  $dstamp = strtotime("$ckdate");
1565 
1566  $wday = date("w", $dstamp); # day of week 0=Sunday
1567  switch ($wday) {
1568  case 1: # Monday, back up to Friday
1569  $ymd = date("Ymd", $dstamp - (86400 * 3));
1570  break;
1571  default: # back up one day
1572  $ymd = date("Ymd", $dstamp - 86400);
1573  break;
1574  }
1575  # build list of holidays for year of ckdate
1576  # if we landed on a holiday, back up to the prior workday from the array
1577  $year = substr($ymd, 0, 4);
1578  $holidays = BumpHolidays($year, $year);
1579  if (array_key_exists($ymd, $holidays)) {
1580  $ymd = $holidays[$ymd];
1581  }
1582 
1583  return $ymd;
1584  }
1585 
1586 /**
1587  * FedImageSI retrieves a single image from FedImage service
1588  * @global array $parms used to get the settings for vendor logging
1589  * @param string $Cu client code cuadmin.cu
1590  * @param string $src link to retrieve the image
1591  * @param string $certfile name of client sslcert in /home/{cu}/sslforms
1592  * @param string $pass password for the client sslcert
1593  * @param string $server FedImage URL
1594  * @return string base64 encoded image bytes
1595  */
1596  function FedImageSI($Cu, $src, $certfile, $pass, $server) {
1597 
1598  $response = "";
1599  # using hard-coded path instead of HB_ENV['cloudfrontDomainName']
1600  # because this runs from both banking and admin (HB_ENV undefined in admin)
1601  $nocheck = "https://d1kryjpwpzirc7.cloudfront.net/odyssey/images/nochecksgl.gif";
1602  $nctypehead = "data:image/gif";
1603  $front = "Check Image Not Found";
1604 
1605  $cmd = "/usr/bin/curl --silent -E $certfile:$pass $src";
1606 
1607  $curlopts = array(
1608  CURLOPT_RETURNTRANSFER => 1,
1609  CURLOPT_SSL_VERIFYPEER => 0,
1610  CURLOPT_SSL_VERIFYHOST => 0,
1611  CURLOPT_HEADER => FALSE,
1612  CURLOPT_SSLCERT => $certfile,
1613  CURLOPT_SSLCERTPASSWD => $pass,
1614  CURLOPT_URL => "$src");
1615 // $reqHeaders = array('Content-Type: text/xml');
1616  $reqHeaders = array();
1617 
1618  $ch = curl_init();
1619 //curl_setopt($ch, CURLOPT_VERBOSE, true);
1620 //$verbose = fopen('/tmp/fstrace', 'a+');
1621 //curl_setopt($ch, CURLOPT_STDERR, $verbose);
1622 
1623  curl_setopt_array($ch, $curlopts);
1624 // curl_setopt($ch, CURLOPT_HTTPHEADER, $reqHeaders);
1625 
1626  $respERR = '';
1627  $imagebytes = curl_exec($ch);
1628  $respHTTP = curl_getinfo($ch, CURLINFO_HTTP_CODE);
1629  $respTYPE = curl_getinfo($ch, CURLINFO_CONTENT_TYPE); # gets NULL if no valid Content-Type
1630  $respCURL = curl_errno($ch);
1631 
1632  if ($respCURL) {
1633  # curl error
1634  $respERR = "HCUERROR: Connection Failed cURL $respCURL";
1635  } elseif ($respHTTP > 400 && $respHTTP < 600) {
1636  # HTTP Response 4xx client error or 5xx server error
1637  $respERR = "HCUERROR: Connection Failed HTTP $respHTTP ";
1638  } elseif (!isset($imagebytes) || $imagebytes == '') {
1639  # no response
1640  $respERR = "HCUERROR: Empty Response";
1641  } elseif (is_null($respTYPE) || strtolower(substr($respTYPE, 0, 5)) != 'image') {
1642  # Content-Type header missing or not an image
1643  $respERR = "HCUERROR: Response Not an Image";
1644  } else {
1645  # should be good response
1646  $theader = "data:" . trim($respTYPE);
1647  }
1648 
1649  global $parms;
1650  if (HCU_array_key_value("logging", $parms) == "enabled") {
1651  $logParms = $parms["environment"]; // get the environment info passed in
1652  $logParms["token"] = ''; // the id used across all communications in session
1653  $logParms["txnId"] = time(); // the id for this transaction
1654  $logParms["logPoint"] = "FedImage SI"; // this action in a readable form
1655  $logParms["request"] = "$cmd"; // the request
1656  $logParms["reply"] = "$respERR\n"; // the response
1657  if (is_null($respTYPE) || strtolower(substr($respTYPE, 0, 5)) != 'image') {
1658  $logParms["reply"] .= $imagebytes; // response from core
1659  } else {
1660  $logParms["reply"] .= "(IMAGE DATA)\n"; // This is a string
1661  }
1662  LogSSOActivity($logParms);
1663  }
1664 
1665  if ($respERR != '') {
1666  $theader = $nctypehead;
1667  $imagebytes = file_get_contents($nocheck);
1668  }
1669 
1670  return $theader . ';base64,' . base64_encode($imagebytes);
1671  }
1672 
1673 /**
1674  * FedImageGL gets the links for front & back images for a particular check
1675  * FedImage check retrieval works in 2 steps. This function is the first
1676  * step, getting the links for the front and back of the requested check
1677  *
1678  * @global array $parms used to pass in the settings for vendor logging
1679  * @param string $Cu client code cuadmin.cu
1680  * @param string $ckdate home banking date accounthistory.date
1681  * @param currency $amount check amount accounthistory.amount
1682  * @param string $check check number accounthistory.checknumber
1683  * @param string $rt cu routing & transit (ABA) number cuadmin.rt
1684  * @param string $micr member micr accountbalance.micraccount
1685  * @param string $sk accounthistory.sortkey - contains tracenumber
1686  * @param string $bytrace some clients retrieve by trace# instead of micr /check#
1687  * @param string $certfile name of client sslcert in /home/{cu}/sslforms
1688  * @param string $pass password for the client sslcert
1689  * @param string $server FedImage URL
1690  * @return array w/status and, if found, the base64 encoded image bytes
1691  */
1692  function FedImageGL($Cu, $ckdate, $amount, $check, $rt, $micr, $sk, $bytrace, $certfile, $pass, $server) {
1693  # get links to images (front and back?)
1694 # "/FedImage?cu=$Cu&mode=gl&date=$date&amount=$amount&check=$check&rt=$rt&micr=$micr&sk=$sk&bytrace=$bytrace{$inc_adm}&imgkey=$imgkey";
1695  /*
1696  # FedSpecs.i provides 4 variables per client:
1697  $fvtype="BW" for everyone
1698  $certfile=path to client certificate
1699  $passwd=password for client certificate
1700  $server="https://www.federalreserve.org/image/DexGateway/servlets/DexGateway";
1701  *
1702  * change to set these in the monitor, and then FedSpecs.i is not needed
1703  */
1704 
1705 # get link to image
1706  $fvtype = "BW";
1707  $ymd = ( substr($ckdate, 6, 4) . substr($ckdate, 0, 2) . substr($ckdate, 3, 2));
1708  $amt = str_replace(".", "", $amount);
1709 
1710  $dxml = "<?xml version=\"1.0\" encoding=\"utf-8\"?>
1711 <requestPackage>
1712 <itemRequest>
1713 <userRequestId>user</userRequestId>
1714 <description>Retrieve images</description>
1715 <itemSelection>
1716 <itemType>both</itemType>
1717 <timeout>100</timeout>
1718 <maxItemsReturned>1</maxItemsReturned>
1719 <criteria>
1720 <connector>AND</connector>
1721 <field>
1722 <name>Routing and Transit Number</name>
1723 <operator>EQ</operator>
1724 <value>$rt</value>
1725 </field>
1726 <field>
1727 <name>Process Date</name>
1728 <operator>EQ</operator>
1729 <value>$ymd</value>
1730 </field>
1731 ";
1732  if ($bytrace == 1) {
1733  # query by Item Sequence Number
1734  $dxml .= "<field>
1735 <name>Item Sequence Number</name>
1736 <operator>EQ</operator>
1737 <value>$sk</value>
1738 </field>
1739 ";
1740  } elseif ($bytrace == 2) {
1741  # Tongass business accounts have check# in Aux On Us instead
1742  $dxml .= "<field>
1743 <name>Aux On Us</name>
1744 <operator>EQ</operator>
1745 <value>$check</value>
1746 </field>
1747 ";
1748  } else {
1749  $dxml .= "<field>
1750 ";
1751  if ($Cu == 'SFEFCU' || $Cu == 'IUCU') {
1752  $dxml .= "<name>Check Number</name>
1753 ";
1754  } else {
1755  $dxml .= "<name>Process Control</name>
1756 ";
1757  }
1758  $dxml .= "<operator>EQ</operator>
1759 <value>$check</value>
1760 </field>
1761 ";
1762  }
1763  $dxml .="<field>
1764 <name>Account Number</name>
1765 <operator>EQ</operator>
1766 <value>$micr</value>
1767 </field>
1768 <field>
1769 <name>Amount</name>
1770 <operator>EQ</operator>
1771 <value>$amt</value>
1772 </field>
1773 </criteria>
1774 <view>
1775 <viewType>F$fvtype</viewType>
1776 <compression>PNG</compression>
1777 <density>0</density>
1778 <binarize>0</binarize>
1779 </view>
1780 <view>
1781 <viewType>B$fvtype</viewType>
1782 <compression>PNG</compression>
1783 <density>0</density>
1784 <binarize>0</binarize>
1785 </view>
1786 </itemSelection>
1787 </itemRequest>
1788 </requestPackage>";
1789 
1790  $response = "";
1791  # using hard-coded path instead of HB_ENV['cloudfrontDomainName']
1792  # because this runs from both banking and admin (HB_ENV undefined in admin)
1793  $nocheck = "https://d1kryjpwpzirc7.cloudfront.net/odyssey/images/nochecksgl.gif";
1794  $nctypehead = "data:image/gif";
1795  $front = "Check Image Not Found";
1796  $back = "NO";
1797 
1798  $cmd = "/usr/bin/curl --silent --data-binary '$dxml' -H 'Content-Type: text/xml' -E $certfile:$pass $server";
1799 
1800 # use embedded curl to get results, check errors
1801 
1802  $curlopts = array(
1803  CURLOPT_RETURNTRANSFER => 1,
1804  CURLOPT_SSL_VERIFYPEER => 0,
1805  CURLOPT_SSL_VERIFYHOST => 0,
1806  CURLOPT_HEADER => FALSE,
1807  CURLOPT_SSLCERT => $certfile,
1808  CURLOPT_SSLCERTPASSWD => $pass,
1809  CURLOPT_POSTFIELDS => $dxml,
1810  CURLOPT_URL => "$server");
1811  $reqHeaders = array('Content-Type: text/xml');
1812 
1813  $ch = curl_init();
1814 //curl_setopt($ch, CURLOPT_VERBOSE, true);
1815 //$verbose = fopen('/tmp/fstrace', 'a+');
1816 //curl_setopt($ch, CURLOPT_STDERR, $verbose);
1817 
1818  curl_setopt_array($ch, $curlopts);
1819  curl_setopt($ch, CURLOPT_HTTPHEADER, $reqHeaders);
1820 
1821  $respERR = 'Success';
1822  $response = curl_exec($ch);
1823  $respHTTP = curl_getinfo($ch, CURLINFO_HTTP_CODE);
1824  $respTYPE = curl_getinfo($ch, CURLINFO_CONTENT_TYPE); # gets NULL if no valid Content-Type
1825  $respCURL = curl_errno($ch);
1826 
1827  if ($respCURL) {
1828  # curl error
1829  $respERR = "HCUERROR: Connection Failed cURL $respCURL";
1830  } elseif ($respHTTP > 400 && $respHTTP < 600) {
1831  # HTTP Response 4xx client error or 5xx server error
1832  $respERR = "HCUERROR: Connection Failed HTTP $respHTTP ";
1833  } elseif (!isset($response) || $response == '') {
1834  # no response
1835  $respERR = "HCUERROR: Empty Response";
1836  }
1837 
1838  if ($respERR == 'Success') {
1839 # got this far, guess good document first -
1840 # but try to handle xml load errors
1841  # set xml to catch errors, and remember the current setting
1842  $xmlerr_setting = libxml_use_internal_errors(true);
1843 
1844  $xml = simplexml_load_string($response);
1845 
1846  # retrieve any errors encountered on the load
1847  $xmlerrors = libxml_get_errors();
1848  # clear the internal buffer
1849  libxml_clear_errors();
1850  # put the setting back to previous state
1851  libxml_use_internal_errors($xmlerr_setting);
1852 
1853  if ($xml === FALSE ) {
1854  # if we need to print ea. error this would do it
1855  # but really just want to know the doc. didn't load
1856 // foreach($xmlerrors as $error) {
1857 // echo "\t", $error->message;
1858 // }
1859  $respERR = "HCUERROR: Invalid XML";
1860  $imagebytes = file_get_contents($nocheck);
1861  $front = $nctypehead . ';base64,' . base64_encode($imagebytes);
1862  $back = "NO";
1863  } else {
1864  $respCode = $xml->xpath("//returnCode");
1865  $retcode = 0;
1866  foreach ($respCode as $code) {
1867  $retcode += $code;
1868  }
1869 # check that $retcode == 0 ?
1870  $respLinks = $xml->xpath("//imageKey");
1871  if (HCU_array_key_value(0,$respLinks) && HCU_array_key_value(1,$respLinks)) {
1872  $front = FedImageSI($Cu, $respLinks[0], $certfile, $pass, $server);
1873  $back = FedImageSI($Cu, $respLinks[1], $certfile, $pass, $server);
1874  } else {
1875  $respERR = "HCUERROR: No Image Links ($retcode)";
1876  $imagebytes = file_get_contents($nocheck);
1877  $front = $nctypehead . ';base64,' . base64_encode($imagebytes);
1878  $back = "NO";
1879  }
1880  }
1881  }
1882 
1883  global $parms;
1884  if (HCU_array_key_value("logging", $parms) == "enabled") {
1885  $logParms = $parms["environment"]; // get the environment info passed in
1886  $logParms["token"] = ''; // the id used across all communications in session
1887  $logParms["txnId"] = time(); // the id for this transaction
1888  $logParms["logPoint"] = "FedImage GL"; // this action in a readable form
1889  $logParms["request"] = "$cmd"; // the request
1890  $logParms["reply"] = "$respERR\n$response"; // the response
1891  LogSSOActivity($logParms);
1892  }
1893 # Status = 'Success' or error message
1894  return array('Status' => $respERR, 'Front' => $front, 'Back' => $back);
1895  }
1896 /**
1897  * BumpHolidays Builds a list of federal holidays between $Start & $End
1898  * and a corresponding substitute processing date to be used for image retrieval
1899  * @param string $Start beginning year
1900  * @param string $End ending year
1901  * @return array holiday dates & respective substitute date
1902  */
1903  function BumpHolidays($Start, $End) {
1904 //================================================= ================
1905 //This function programmatically determines Federal Holidays landing
1906 // between the given start and end YY
1907 // adapted from code Written by Jana Bauer,
1908 // which was adapted from code obtained at
1909 //http://www.tek-tips.com/faqs.cfm?fid=6003
1910 //
1911 //adapted 2017 to return list of holiday & corresponding previous work day
1912 //================================================= ================
1913 
1914  $holidays = array();
1915  for ($i = $Start; $i <= $End; $i++) {
1916  for ($m = 1; $m <= 12; $m++) {
1917  switch ($m) {
1918  case 3:
1919  case 4:
1920  case 6:
1921  case 8:
1922 // No holidays in these months
1923  break;
1924 
1925  case 1:
1926  // New Year's Day 1/1 or closest Monday / Friday
1927  $dtHoliday = mktime(12, 0, 0, 1, 1, $i);
1928  $dtHoliday = GetNearestWeekday($dtHoliday);
1929  $holidays[date('Ymd', $dtHoliday)] = date('Ymd', GetPreviousWeekday($dtHoliday));
1930  // MLK Day 3rd Monday in January
1931  $dow = idate('w', $dtHoliday);
1932  # find first Monday
1933  switch ($dow) {
1934  case 0: #Sunday
1935  $dtHoliday += 86400;
1936  break;
1937  case 1: #already Monday
1938  break;
1939  case 2:
1940  $dtHoliday += (86400 * 6);
1941  break;
1942  case 3:
1943  $dtHoliday += (86400 * 5);
1944  break;
1945  case 4:
1946  $dtHoliday += (86400 * 4);
1947  break;
1948  case 5:
1949  $dtHoliday += (86400 * 3);
1950  break;
1951  case 6:
1952  $dtHoliday += (86400 * 2);
1953  break;
1954  }
1955  $dtHoliday += (86400 * 14); # add 2 weeks to get 3rd Monday
1956  $holidays[date('Ymd', $dtHoliday)] = date('Ymd', GetPreviousWeekday($dtHoliday));
1957  break;
1958 
1959  case 2:
1960  // President's Day 3rd Monday in February
1961  $dtHoliday = mktime(12, 0, 0, 2, 1, $i);
1962  $dow = idate('w', $dtHoliday);
1963  # find first Monday
1964  switch ($dow) {
1965  case 0: #Sunday
1966  $dtHoliday += 86400;
1967  break;
1968  case 1: #already Monday
1969  break;
1970  case 2:
1971  $dtHoliday += (86400 * 6);
1972  break;
1973  case 3:
1974  $dtHoliday += (86400 * 5);
1975  break;
1976  case 4:
1977  $dtHoliday += (86400 * 4);
1978  break;
1979  case 5:
1980  $dtHoliday += (86400 * 3);
1981  break;
1982  case 6:
1983  $dtHoliday += (86400 * 2);
1984  break;
1985  }
1986  $dtHoliday += (86400 * 14); # add 2 weeks to get 3rd Monday
1987  $holidays[date('Ymd', $dtHoliday)] = date('Ymd', GetPreviousWeekday($dtHoliday));
1988  break;
1989 
1990  case 5:
1991  // Memorial Day Last Monday in May
1992  $dtHoliday = mktime(12, 0, 0, 5, 31, $i);
1993  $dow = idate('w', $dtHoliday);
1994  # find last day & back up
1995  switch ($dow) {
1996  case 0: #Sunday
1997  $dtHoliday -= (86400 * 6);
1998  break;
1999  case 1: #already Monday
2000  break;
2001  case 2:
2002  $dtHoliday -= 86400;
2003  break;
2004  case 3:
2005  $dtHoliday -= (86400 * 2);
2006  break;
2007  case 4:
2008  $dtHoliday -= (86400 * 3);
2009  break;
2010  case 5:
2011  $dtHoliday -= (86400 * 4);
2012  break;
2013  case 6:
2014  $dtHoliday -= (86400 * 5);
2015  break;
2016  }
2017  $holidays[date('Ymd', $dtHoliday)] = date('Ymd', GetPreviousWeekday($dtHoliday));
2018  break;
2019 
2020  case 7:
2021  // Independence Day 7/4 or Closest Friday / Monday
2022  $dtHoliday = mktime(12, 0, 0, 7, 4, $i);
2023  $dtHoliday = GetNearestWeekday($dtHoliday);
2024  $holidays[date('Ymd', $dtHoliday)] = date('Ymd', GetPreviousWeekday($dtHoliday));
2025 
2026  break;
2027 
2028  case 9:
2029  // Labor Day 1st Monday in September
2030  $dtHoliday = mktime(12, 0, 0, 9, 1, $i);
2031  $dow = idate('w', $dtHoliday);
2032  # find first Monday
2033  switch ($dow) {
2034  case 0: #Sunday
2035  $dtHoliday += 86400;
2036  break;
2037  case 1: #already Monday
2038  break;
2039  case 2:
2040  $dtHoliday += (86400 * 6);
2041  break;
2042  case 3:
2043  $dtHoliday += (86400 * 5);
2044  break;
2045  case 4:
2046  $dtHoliday += (86400 * 4);
2047  break;
2048  case 5:
2049  $dtHoliday += (86400 * 3);
2050  break;
2051  case 6:
2052  $dtHoliday += (86400 * 2);
2053  break;
2054  }
2055  $holidays[date('Ymd', $dtHoliday)] = date('Ymd', GetPreviousWeekday($dtHoliday));
2056  break;
2057 
2058  case 10:
2059  // Columbus Day 2nd Monday in October
2060  $dtHoliday = mktime(12, 0, 0, 10, 1, $i);
2061  $dow = idate('w', $dtHoliday);
2062  # find first Monday
2063  switch ($dow) {
2064  case 0: #Sunday
2065  $dtHoliday += 86400;
2066  break;
2067  case 1: #already Monday
2068  break;
2069  case 2:
2070  $dtHoliday += (86400 * 6);
2071  break;
2072  case 3:
2073  $dtHoliday += (86400 * 5);
2074  break;
2075  case 4:
2076  $dtHoliday += (86400 * 4);
2077  break;
2078  case 5:
2079  $dtHoliday += (86400 * 3);
2080  break;
2081  case 6:
2082  $dtHoliday += (86400 * 2);
2083  break;
2084  }
2085  $dtHoliday += (86400 * 7); # add 1 week to get 2nd Monday
2086  $holidays[date('Ymd', $dtHoliday)] = date('Ymd', GetPreviousWeekday($dtHoliday));
2087  break;
2088 
2089  case 11:
2090  // Veteran's Day 11/11 or Following Monday
2091  $dtHoliday = mktime(12, 0, 0, 11, 11, $i);
2092  $dtHoliday = GetNearestWeekday($dtHoliday);
2093  $holidays[date('Ymd', $dtHoliday)] = date('Ymd', GetPreviousWeekday($dtHoliday));
2094 
2095  // Thanksgiving Day 4th Thursday in November
2096  $dtHoliday = mktime(12, 0, 0, 11, 1, $i);
2097  $dow = idate('w', $dtHoliday);
2098  # find first Thursday
2099  switch ($dow) {
2100  case 0: #Sunday
2101  $dtHoliday += (86400 * 4);
2102  break;
2103  case 1: #Monday
2104  $dtHoliday += (86400 * 3);
2105  break;
2106  case 2:
2107  $dtHoliday += (86400 * 2);
2108  break;
2109  case 3:
2110  $dtHoliday += 86400;
2111  break;
2112  case 4:
2113  break;
2114  case 5:
2115  $dtHoliday += (86400 * 6);
2116  break;
2117  case 6:
2118  $dtHoliday += (86400 * 5);
2119  break;
2120  }
2121  $dtHoliday += (86400 * 21); # add 3 weeks to get 4th Thursday
2122  $holidays[date('Ymd', $dtHoliday)] = date('Ymd', GetPreviousWeekday($dtHoliday));
2123  break;
2124 
2125  case 12:
2126  // Christmas Day 12/25 or closest Friday / Monday
2127  $dtHoliday = mktime(12, 0, 0, 12, 25, $i);
2128  $dtHoliday = GetNearestWeekday($dtHoliday);
2129  $holidays[date('Ymd', $dtHoliday)] = date('Ymd', GetPreviousWeekday($dtHoliday));
2130 
2131  break;
2132  }
2133  }
2134  }
2135 
2136  return $holidays;
2137  }
2138 
2139  /**
2140  * GetPreviousWeekday Returns previous week day
2141  * Sunday & Monday move to previous Friday
2142  * Tues - Saturday move backward one day
2143  * @param timestamp $dtTimeStamp date to be examined
2144  * @return int timestamp of adjusted day
2145  */
2146  Function GetPreviousWeekday($dtTimeStamp) {
2147 //Note Sunday = 0, Saturday = 6
2148  $intWeekday = idate('w', $dtTimeStamp);
2149  switch ($intWeekday) {
2150  case 0: #Sunday - move back to Friday
2151  $dtTimeStamp -= (2 * 86400);
2152  break;
2153  case 1: # Monday - move back to Friday
2154  $dtTimeStamp -= (3 * 86400);
2155  break;
2156  case 2:# Tuesday - Saturday - move back one day
2157  case 3:
2158  case 4:
2159  case 5:
2160  case 6:
2161  default:
2162  $dtTimeStamp -= 86400;
2163  break;
2164  }
2165  return $dtTimeStamp;
2166  }
2167 
2168  /**
2169  * GetNearestWeekday adjusts timestamp if needed to hit a weekday
2170  * @param timestamp $dtTimeStamp date to examine
2171  * @return int timestamp adjusted to nearest weekday -
2172  * Sunday moves forward to Monday
2173  * Saturday moves back to Friday
2174  */
2175  Function GetNearestWeekday($dtTimeStamp) {
2176 //Note Sunday = 0, Saturday = 6
2177  $intWeekday = idate('w', $dtTimeStamp);
2178  switch ($intWeekday) {
2179  case 0: #Sunday - move forward to Monday
2180  $dtTimeStamp += 86400;
2181  break;
2182  case 6: #Saturday - move back to Friday
2183  $dtTimeStamp -= 86400;
2184  break;
2185  case 1: # Monday - Friday - do nothing
2186  case 2:
2187  case 3:
2188  case 4:
2189  case 5:
2190  default:
2191  break;
2192  }
2193  return $dtTimeStamp;
2194  }
2195 ?>