|
| 1 | +<?php |
| 2 | + |
| 3 | +use Fhp\CurlException; |
| 4 | +use Fhp\Protocol\ServerException; |
| 5 | +use Fhp\Protocol\UnexpectedResponseException; |
| 6 | + |
| 7 | +/** |
| 8 | + * SAMPLE - Helper functions for Verification of Payee. To be used together with init.php. |
| 9 | + */ |
| 10 | + |
| 11 | +/** @var \Fhp\FinTs $fints */ |
| 12 | +$fints = require_once 'init.php'; |
| 13 | + |
| 14 | +/** |
| 15 | + * To be called after the $action was already executed, this function takes care of asking the user for a TAN and VOP |
| 16 | + * confirmation, if necessary. |
| 17 | + * @param \Fhp\BaseAction $action The action, which must already have been run through {@link \Fhp\FinTs::execute()}. |
| 18 | + * @throws CurlException|UnexpectedResponseException|ServerException See {@link FinTs::execute()} for details. |
| 19 | + */ |
| 20 | +function handleVopAndAuthentication(\Fhp\BaseAction $action): void |
| 21 | +{ |
| 22 | + // NOTE: This is implemented as a `while` loop here, because this sample script runs entirely in one PHP process. |
| 23 | + // If you want to make real use of the serializations demonstrated below, in order to resume processing in a new |
| 24 | + // PHP process later (once the user has responded via your browser/client-side application), then you won't have a |
| 25 | + // loop like this, but instead you'll just run the code within each time you get a new request from the user. |
| 26 | + while (!$action->isDone()) { |
| 27 | + if ($action->needsTan()) { |
| 28 | + handleStrongAuthentication($action); // See login.php for the implementation. |
| 29 | + } elseif ($action->needsPollingWait()) { |
| 30 | + handlePollingWait($action); |
| 31 | + } elseif ($action->needsVopConfirmation()) { |
| 32 | + handleVopConfirmation($action); |
| 33 | + } else { |
| 34 | + throw new \AssertionError( |
| 35 | + 'Action is not done but also does not need anything to be done. Did you execute() it?' |
| 36 | + ); |
| 37 | + } |
| 38 | + } |
| 39 | +} |
| 40 | + |
| 41 | +/** |
| 42 | + * Waits for the amount of time that the bank prescribed and then polls the server for a status update. |
| 43 | + * @param \Fhp\BaseAction $action An action for which {@link \Fhp\BaseAction::needsPollingWait()} returns true. |
| 44 | + * @throws CurlException|UnexpectedResponseException|ServerException See {@link FinTs::execute()} for details. |
| 45 | + */ |
| 46 | +function handlePollingWait(\Fhp\BaseAction $action): void |
| 47 | +{ |
| 48 | + global $fints, $options, $credentials; // From login.php |
| 49 | + |
| 50 | + // Tell the user what the bank had to say (if anything). |
| 51 | + $pollingInfo = $action->getPollingInfo(); |
| 52 | + if ($infoText = $pollingInfo->getInformationForUser()) { |
| 53 | + echo $infoText . PHP_EOL; |
| 54 | + } |
| 55 | + |
| 56 | + // Optional: If the wait is too long for your PHP process to remain alive (i.e. your server would kill the process), |
| 57 | + // you can persist the state as shown here and instead send a response to the client-side application indicating |
| 58 | + // that the operation is still ongoing. Then after an appropriate amount of time, the client can send another |
| 59 | + // request, spawning a new PHP process, where you can restore the state as shown below. |
| 60 | + if ($optionallyPersistEverything = false) { |
| 61 | + $persistedAction = serialize($action); |
| 62 | + $persistedFints = $fints->persist(); |
| 63 | + |
| 64 | + // These are two strings (watch out, they are NOT necessarily UTF-8 encoded), which you can store anywhere. |
| 65 | + // This example code stores them in a text file, but you might write them to your database (use a BLOB, not a |
| 66 | + // CHAR/TEXT field to allow for arbitrary encoding) or in some other storage (possibly base64-encoded to make it |
| 67 | + // ASCII). |
| 68 | + file_put_contents(__DIR__ . '/state.txt', serialize([$persistedFints, $persistedAction])); |
| 69 | + } |
| 70 | + |
| 71 | + // Wait for (at least) the prescribed amount of time. -------------------------------------------------------------- |
| 72 | + // Note: In your real application, you may be doing this waiting on the client and then send a fresh request to your |
| 73 | + // server. |
| 74 | + $waitSecs = $pollingInfo->getNextAttemptInSeconds() ?: 5; |
| 75 | + echo "Waiting for $waitSecs seconds before polling the bank server again..." . PHP_EOL; |
| 76 | + sleep($waitSecs); |
| 77 | + |
| 78 | + // Optional: If the state was persisted above, we can restore it now (imagine this is a new PHP process). |
| 79 | + if ($optionallyPersistEverything) { |
| 80 | + $restoredState = file_get_contents(__DIR__ . '/state.txt'); |
| 81 | + list($persistedInstance, $persistedAction) = unserialize($restoredState); |
| 82 | + $fints = \Fhp\FinTs::new($options, $credentials, $persistedInstance); |
| 83 | + $action = unserialize($persistedAction); |
| 84 | + } |
| 85 | + |
| 86 | + $fints->pollAction($action); |
| 87 | + // Now the action is in a new state, which the caller of this function (handleVopAndAuthentication) will deal with. |
| 88 | +} |
| 89 | + |
| 90 | +/** |
| 91 | + * Asks the user to confirm |
| 92 | + * @param \Fhp\BaseAction $action An action for which {@link \Fhp\BaseAction::needsVopConfirmation()} returns true. |
| 93 | + * @throws CurlException|UnexpectedResponseException|ServerException See {@link FinTs::execute()} for details. |
| 94 | + */ |
| 95 | +function handleVopConfirmation(\Fhp\BaseAction $action): void |
| 96 | +{ |
| 97 | + global $fints, $options, $credentials; // From login.php |
| 98 | + |
| 99 | + $vopConfirmationRequest = $action->getVopConfirmationRequest(); |
| 100 | + if ($infoText = $vopConfirmationRequest->getInformationForUser()) { |
| 101 | + echo $infoText . PHP_EOL; |
| 102 | + } |
| 103 | + echo match ($vopConfirmationRequest->getVerificationResult()) { |
| 104 | + \Fhp\Model\VopVerificationResult::CompletedFullMatch => |
| 105 | + 'The bank says the payee information matched perfectly, but still wants you to confirm.', |
| 106 | + \Fhp\Model\VopVerificationResult::CompletedCloseMatch => |
| 107 | + 'The bank says the payee information does not match exactly, so please confirm.', |
| 108 | + \Fhp\Model\VopVerificationResult::CompletedPartialMatch => |
| 109 | + 'The bank says the payee information does not match for all transfers, so please confirm.', |
| 110 | + \Fhp\Model\VopVerificationResult::CompletedNoMatch => |
| 111 | + 'The bank says the payee information does not match, but you can still confirm the transfer if you want.', |
| 112 | + \Fhp\Model\VopVerificationResult::NotApplicable => |
| 113 | + $vopConfirmationRequest->getVerificationNotApplicableReason() == null |
| 114 | + ? 'The bank did not provide any information about payee verification, but you can still confirm.' |
| 115 | + : 'The bank says: ' . $vopConfirmationRequest->getVerificationNotApplicableReason(), |
| 116 | + default => 'The bank failed to provide information about payee verification, but you can still confirm.', |
| 117 | + } . PHP_EOL; |
| 118 | + |
| 119 | + // Just like in handleTan(), handleDecoupledSubmission() or handlePollingWait(), we have the option to interrupt the |
| 120 | + // PHP process at this point, so that we can ask the user in a client application for their confirmation. |
| 121 | + if ($optionallyPersistEverything = false) { |
| 122 | + $persistedAction = serialize($action); |
| 123 | + $persistedFints = $fints->persist(); |
| 124 | + // See handlePollingWait() for how to deal with this in practice. |
| 125 | + file_put_contents(__DIR__ . '/state.txt', serialize([$persistedFints, $persistedAction])); |
| 126 | + } |
| 127 | + |
| 128 | + echo "In light of the information provided above, do you want to confirm the execution of the transfer?" . PHP_EOL; |
| 129 | + // Note: We currently have no way canceling the transfer; the only thing we can do is never to confirm it. |
| 130 | + echo "If so, please type 'confirm' and hit Return. Otherwise, please kill this PHP process." . PHP_EOL; |
| 131 | + while (trim(fgets(STDIN)) !== 'confirm') { |
| 132 | + echo "Try again." . PHP_EOL; |
| 133 | + } |
| 134 | + echo "Confirming the transfer." . PHP_EOL; |
| 135 | + $fints->confirmVop($action); |
| 136 | + echo "Confirmed" . PHP_EOL; |
| 137 | + // Now the action is in a new state, which the caller of this function (handleVopAndAuthentication) will deal with. |
| 138 | +} |
0 commit comments