summaryrefslogtreecommitdiff
path: root/php/doc/tutorial.texi
blob: 686b6d335f824c709b8d3b7ebcfd16e4e430c822 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
\input texinfo @c -*-texinfo-*-
@c %**start of header
@setfilename tutorial.info
@include ../../common/version.texi
@include ../../common/texi/syntax.texi
@settitle The GNU Taler tutorial for PHP Web shop developers @value{VERSION}

@c Define a new index for options.
@defcodeindex op
@c Combine everything into one index (arbitrarily chosen to be the
@c concept index).
@syncodeindex op cp
@c %**end of header

@copying
This tutorial is about implementing a merchant frontend to run against a
GNU Taler merchant backend (version @value{VERSION}, @value{UPDATED}),

Copyright @copyright{} 2016, 2017 Taler Systems SA

@quotation
Permission is granted to copy, distribute and/or modify this document
under the terms of the GNU Free Documentation License, Version 1.3 or
any later version published by the Free Software Foundation; with no
Invariant Sections, with no Front-Cover Texts, and with no Back-Cover
Texts.  A copy of the license is included in the section entitled
``GNU Free Documentation License''.
@end quotation
@end copying
@c If your tutorial is published on paper by the FSF, it should include
@c The standard FSF Front-Cover and Back-Cover Texts, as given in
@c maintain.texi.
@c
@c Titlepage
@c
@titlepage
@title The GNU Taler tutorial for PHP Web shops
@subtitle Version @value{VERSION}
@subtitle @value{UPDATED}
@author Marcello Stanisci (@email{marcello.stanisci@@inria.fr})
@author Christian Grothoff (@email{christian.grothoff@@inria.fr}
@author Florian Dold (@email{florian.dold@@inria.fr})
@page
@vskip 0pt plus 1filll
@insertcopying
@end titlepage

@summarycontents
@contents

@ifnottex
@node Top
@top The GNU Taler tutorial for PHP Web shops
@insertcopying
@end ifnottex

@menu
* Introduction::            Whom this tutorial is addressed to
* Hello-world::             How to set up a donation page
* Back-office-integration:: How to integrate with the back office
* Advanced topics::         Detailed solutions to specific issues
* Reference::               Merchant integration reference


Appendices

* GNU-LGPL::                     The GNU Lesser General Public License says how you
                                 can use the code of libtalermerchant.so in your own projects.
* GNU-FDL::                      The GNU Free Documentation License says how you
                                 can copy and share the documentation of GNU Taler.

Indices

* Concept Index::               Index of concepts and programs.
@end menu


@node Introduction
@chapter Introduction

@section About GNU Taler

GNU Taler is an open protocol for an electronic payment system with a
free software reference implementation.  GNU Taler offers secure, fast
and easy payment processing using well understood cryptographic
techniques.  GNU Taler allows customers to remain anonymous, while
ensuring that merchants can be held accountable by governments.
Hence, GNU Taler is compatible with anti-money-laundering (AML) and
know-your-customer (KYC) regulation, as well as data protection
regulation (such as GDPR).


@section About this tutorial

This tutorial is for Web developers and addresses how to integrate GNU
Taler with Web shops. It describes how to create a Web shop that
processes payments with the help of a GNU Taler merchant
@emph{backend}.  In the second chapter, you will learn how to trigger
the payment process from the Web site, how to communicate with the
backend, how to generate a order and process the payment.  The
third chapter covers the integration of a back office with the
backend, which includes tracking payments for orders, matching
payments to orders, and persisting and retrieving contracts.

@cindex examples
@cindex git
You can download all of the code examples given in this tutorial from
@url{https://git.taler.net/merchant-frontend-examples.git/tree/php/}.

@c Add section giving an overview of what we will do in the tutorial!


@section Architecture overview

The Taler software stack for a merchant consists of the following
main components:

@itemize
@cindex frontend
@item A frontend which interacts with the customer's browser. The
  frontend enables the customer to build a shopping cart and place
  an order.  Upon payment, it triggers the respective business logic
  to satisfy the order.  This component is not included with Taler,
  but rather assumed to exist at the merchant. This tutorial
  describes how to develop a Taler frontend.
@cindex back office
@item A back office application that enables the shop operators to
  view customer orders, match them to financial transfers, and possibly
  approve refunds if an order cannot be satisfied.  This component is
  again not included with Taler, but rather assumed to exist at the
  merchant. This tutorial will describe how to integrate such a component
  to handle payments managed by Taler.  Such integration is shown by
  adding the back office functionality to the frontend implemented
  in the second part of this tutorial.
@cindex backend
@item A Taler-specific payment backend which makes it easy for the
  frontend to process financial transactions with Taler.  For this
  tutorial, you will use a public backend, but for a production
  deployment a merchant-specific backend will need to be setup
  by a system administrator.
@end itemize

The following image illustrates the various interactions of these
key components:

@image{arch, 3in, 4in}


Basically, the backend provides the cryptographic protocol support,
stores Taler-specific financial information and communicates
with the GNU Taler exchange over the Internet.  The frontend accesses
the backend via a RESTful API.  As a result, the frontend never has to
directly communicate with the exchange, and also does not deal with
sensitive data.  In particular, the merchant's signing keys and bank
account information are encapsulated within the Taler backend.

@node Hello-world
@chapter Setting up a simple donation page

This section describes how to setup a simple shop, which exposes a
button to get donations via Taler. The expected behaviour is that once
the ``donate'' button is clicked, the customer will receive a Taler
*proposal* offering him the opportunity to make a fixed donation,
for example to donate 1 KUDOS to the charity operating the shop.

All the code samples shown below in the tutorial can be found at
@url{https://git.taler.net/merchant-frontend-examples.git/tree/php}.

@c NOTE: include explaining wallet installation to Web developer here!

Note that if the customer does not have the Taler wallet installed,
they should instead be prompted to proceed with a classic dialog for
credit card payments.


@section Specifying the backend

@cindex backend
@cindex configuration
@cindex currency
For many critical operations, the frontend needs to communicate
with a Taler backend.  Assuming that you do not yet have a backend
configured, you can use the public backend provided by the Taler
project for testing.  This public backend has been set-up at
@code{http://backend.demo.taler.net/} specifically for testing
frontends.  It uses the currency ``KUDOS'' and all payments will
go into the ``Tutorial'' account at the Taler ``bank'' running at
@code{https://bank.demo.taler.net/public-accounts}.

To point the frontend being developed in this tutorial to some
backend, it suffices to set the variable @code{$BACKEND} in
@code{php/config.php} to the desired backend's base URL.  You also
need to specify the currency used by the backend.  For example:

@smallexample
// php/config.php
@verbatiminclude ../config.php
@end smallexample


@section Talking to the backend

@cindex backend
Given the above configuration, we can now implement two simple
functions @code{get_to_backend} and @code{post_to_backend} to
send requests to the backend.  The function @code{get_to_backend}
is in charge of performing HTTP GET requests to the backend,
while @code{post_to_backend} will send HTTP POST requests.

@smallexample
// php/backend.php
@verbatiminclude ../backend.php
@end smallexample

The given @code{backend.php} code uses a few helper functions from
@code{php/helpers.php}, which should be self-explanatory.


@node Prompting for payment
@section Prompting for payment

@cindex button
Our goal is to trigger a Taler payment once the customer has clicked
on a donation button.  We will use a button that issues an HTTP GET
to the frontend @code{/donate.php} URL.  For this, the HTML would be as
follows:

@smallexample
// php/index.html
@verbatiminclude ../index.html
@end smallexample

When the server-side handler for @code{/donate.php} receives the form submission,
it will return a HTML page that will take care of:

@itemize
@item showing a credit card paywall to the user if no wallet is found, and
@item fetching a Taler proposal and passing it to the wallet if one is found
@end itemize

A minimalistic @code{donate.php} implementation is shown below (in PHP):

@cindex pay handler
@cindex 402
@cindex X-Taler-Contract-Url
@smallexample
// php/donate.php
@verbatiminclude ../donate.php
@end smallexample

Given this response, the Taler wallet will fetch the proposal from
@url{/generate-order.php} and display it to the user.

If the wallet is not present, the HTML body will be shown and the
Taler headers and the 402 status code ought to be ignored by the
browser.

@section A helper function to generate the order

We make distinction between @emph{three} different stages of what it
informally called "contract".

In a very first stage, we call it the @emph{order}: that occurs when
the frontend generates the first JSON that misses some information
that the backend is supposed to add.  When the backend completes the
order and signs it, we have a @emph{proposal}.  The proposal is what
the user is prompted with, and allows them to confirm the purchase.
Once the user confirms the purchase, the wallet makes a signature over
the proposal, turning it into a @emph{contract}.

We first define a helper function @code{make_order} that will
generate a complete Taler order as a nested PHP array.  The
function takes only the order ID and the timestamp as arguments;
all of the other details of the order are hardcoded in this simple
example.

The following code generate a order about donating 1 KUDOS to the
'Taler charity program':

@cindex contract
@smallexample
// php/order.php
@verbatiminclude ../order.php
@end smallexample


@section Signing and returning the proposal

The server-side handler for @code{/generate-order.php} has to call
@code{make_order} and then POST the result to the backend at
@code{/proposal}.  By POSTing the order to the backend we get a
cryptographic signature over its contents.  The result is then
returned to the wallet.

A simple @code{/generate-order.php} handler may thus look like this:

@cindex signature
@cindex backend
@cindex order
@smallexample
// php/generate-order.php
@verbatiminclude ../generate-order.php
@end smallexample

@c FIXME: improve example to do this right?
Note that in practice the frontend might want to generate a monotonically
increasing series of order IDs to avoid a chance of collisions.
Order IDs must be in the range of @math{[0:2^{51})}.

@section Handling errors

In the above example, the helper function @code{build_error} is
used to generate an error response in the case that the backend
somehow failed to respond properly to our request.

The function @code{build_error} is shown below, it returns JSON data
matching a particular format for reporting errors,
see @code{http://api.taler.net/api-common.html#errordetail}:

@smallexample
@c FIXME, build_error() doesn't respect error-reporting format yet!
// php/error.php
@verbatiminclude ../error.php
@end smallexample


@node Initiating the payment process
@section Initiating the payment process

@cindex fulfillment URL
After the browser has fetched the proposal, the user will be
given the opportunity to affirm the payment.  Assuming the user
affirms, the browser will navigate to the ``fulfillment_url'' that
was specified in the proposal.

The fulfillment page can be called by users that have already paid for
the item, as well as by users that have not yet paid at all.  The
fulfillment page must thus use the HTTP session state to detect if the
payment has been performed already, and if not request payment from
the wallet.

For our example, the fulfillment URL will contain the order id of
the donation, like in the following example:

@smallexample
https://shop.com/fulfillment.php?order_id=<ORDER_ID>
@end smallexample

The fulfillment handler at @code{/fulfillment.php} will use this information
to check if the user has already paid, and if so confirm the donation.
If the user has not yet paid, it will instead return another ``402 Payment
Required'' header, requesting the wallet to pay:

@smallexample
// php/fulfillment.php
@verbatiminclude ../fulfillment.php
@end smallexample

@cindex 402 payment required
Here, this second 402 response contains the following Taler-specific
headers:

@table @code
@item X-Taler-Contract-Url
@cindex X-Taler-Contract-Url
The URL that generated the proposal that led to this payment.
The wallet may need to reconstruct the proposal.
@item X-Taler-Contract-Query
@cindex X-Taler-Contract-Query
The way the wallet should lookup for replayable payments.
NOTE that for each payment done, the wallet stores the coins it
spent for it in an internal database. And each set of used coins
is associated to the fulfillment page where they have been spent.
So whenever an already known fulfillment page requests a payment,
the wallet will pick those coins it spent on that fulfillment
page and resend them (therefore @emph{replaying} the payment).
In other words, new coins are used only on unknown fulfillment
pages.
This header is supposed to be removed in future versions of the
wallet though, as it only works with the value @code{"fulfillment_url"}.
@item X-Taler-Offer-Url
@cindex X-Taler-Offer-Url
In case that the wallet does not know about this payment already,
i.e. because a user shared the URL with another user, this tells the
wallet where to go to retrieve a fresh offer.
@end table

@section Receiving payments via Taler

The final next step for the frontend is to accept the payment from the
wallet.  For this, the frontend must implement a payment handler at
the URI specified in the @code{pay_url} proposal field, as explained
above.

The role of the @code{/pay.php} handler is to receive the payment
from the wallet and forward it to the backend.  If the backend
reports that the payment was successful, the handler needs to update
the session state with the browser to remember that the user paid.

The following code implements this in PHP:

@smallexample
// php/pay.php
@verbatiminclude ../pay.php
@end smallexample

Do not be confused by the @code{isset} test for the session state.  In
our simple example, it will be set to ``false'' by the fulfillment URL
which the browser actually always visits first.

After the @code{pay.php} handler has affirmed that the payment was
successful, the wallet will refresh the fulfillment page, this
time receiving the message that the donation was successful.  If
anything goes wrong, the wallet will handle the respective error.

@node Back-office-integration
@chapter Integration with the back office

This chapter shows how to implement the back office Web interface.

We will use the term @emph{transaction} to refer to the business
transaction that a merchant has with a customer (and the related
communication with the Taler exchange for payment), and the term
@emph{wire transfer} to refer to the exchange settling its accounts
with the merchant.

However, from the frontend's perspective, any transaction is denoted
by the @emph{order id} contained in the proposal that led to the
transaction.

Given that Taler deals with microtransactions, not every customer
payment processed with Taler will necessarily correspond to a wire
transfer.  The Taler exchange may aggregate multiple payments from
transactions into one larger wire transfer.  The @var{refund_deadline}
and the @var{pay_deadline} values in the contract specify the
timeframes within which the exchange is permitted to perform such
aggregations, see @ref{The Taler proposal format}.

In this chapter, we will see how a merchant can obtain the
mapping from transactions to wire transfers and vice versa.
Additionally, we will describe how to obtain a list of all
transactions known to the backend.

@section Entry page

Given this charge, the back office's main tasks are:

@itemize
@item
Allow the back office operator to specify a order id, and display the
corresponding wire transfer identifiers.
@item
Allow the back office operator to specify a wire transfer ID, and
display all of the corresponding order ids.
@item
Allow the back office operator to obtain a list of all transactions.
@end itemize

We implement these with a simple HTML form. For simplicity, we have
one single page for gathering input data for both tracking directions:

@smallexample
// php/backoffice.html
@verbatiminclude ../backoffice.html
@end smallexample

The imported script @code{history.js} is responsible for dynamically
get the list of known transactions.  See below.

@section Tracking a transaction

The @code{track-transaction.php} script is now responsible for taking
all the URL query parameter and use them on the @code{/track/transaction}
request to the backend, see @url{http://api.taler.net/api-merchant.html#get--track-transaction}.
The parameters are the @emph{order_id} and the @emph{instance} (see @ref{Instances})
of this merchant.
Note that the backend may then request this information from the
exchange, or retrieve it from its own cache if it has already obtained
it.  The backend will also check signatures from the exchange, persist
the information obtained, and complain if the exchange ever changes
its facts in an inconsistent manner.

@smallexample
// php/track-transaction.php
@verbatiminclude ../track-transaction.php
@end smallexample

If the backend returned an HTTP status code @code{202} (Accepted),
this means that the exchange simply did not yet perform the wire
transfer. This is usually the case before @var{pay_deadline}, as the
exchange is waiting for additional opportunities to aggregate transactions.
In this case, we tell the user when to retry this operation later.

In the @code{foreach} loop, we construct the list of all the
wire transfers which paid back transaction @emph{order_id}.  For
simplicity, the list will report only two values: the wire transfer
identifier and the date when the transfer occurred. Nonetheless,
the data returned by the backend contains more information that
can be shown to the user.

@section Tracking a wire transfer

To track a wire transfer, the frontend just needs to forward the request
it got from the Web form, to the backend.
Again, the backend may request missing information from the exchange,
verify signatures, persist the result and complain if there are
inconsistencies.

In the case that the backend detects inconsistencies, an HTTP status
code of @code{402} is returned.  In this case, we report this
situation to the user, who should now report this situation to the
exchange's auditors as the exchange is misbehaving.

In the usual case where everything went fine, we first output the
amount that was supposed to have been transfered under the given
@code{wtid}, and when it was performed (according to the exchange).
Finally, in the @code{foreach} loop, we construct the list of the
order ids paid by the wire transfer:

@smallexample
@verbatiminclude ../track-transfer.php
@end smallexample


@node History
@section Listing all transactions

In order to track transactions, order ids are needed as input.
To that purpose, the frontend needs to make a HTTP GET request to
@code{/history}, which is offered by the backend.

The returned data lists the transactions from the youngest back to
the oldest.

The @code{/history} API is actually more rich, as it offers the way
to skim results based on time or on index, but that goes beyond the
scope of this tutorial.

Our example frontend implements this feature by orchestrating two
parts:

@itemize
@item A JavaScript function, imported within @code{backoffice.html},
      that issues the HTTP GET to @code{/history.php?instance=tutorial}
      and modifies the current page by adding a table showing the result.
@item The @code{history.php} script, which is in charge of serving the request
      coming from the JavaScript. Its task is to relay that request to the
      backend, and echo the result back.
@end itemize

See below both parts:

@smallexample
// ../history.js
@verbatiminclude ../history.js
@end smallexample

@smallexample
// ../history.php
@verbatiminclude ../history.php
@end smallexample

@node Advanced topics
@chapter Advanced topics

@menu
* Detecting the presence of the Taler wallet::  Detecting the presence of the Taler wallet
* The Taler proposal format::                   The Taler proposal format
* Inlining proposals in HTTP headers::          Inlining proposals in HTTP headers
* Instances::                                   Instances
* The fulfillment page::                        The fulfillment page
* Normalized base URLs::                        Normalized base URLs
@end menu

@include ../../common/texi/wallet-detection.texi
@include ../../common/texi/proposals.texi
@include inline-proposals.texi
@include ../../common/texi/instances.texi
@include ../../common/texi/fulfillment-page.texi
@include ../../common/texi/normalized-base-url.texi


@c ************ Reference chapter ***********
@include ../../common/texi/api-reference.texi

@c **********************************************************
@c *******************  Appendices  *************************
@c **********************************************************

@node GNU-LGPL
@unnumbered GNU-LGPL
@cindex license
@cindex LGPL
@include ../../common/texi/lgpl.texi

@node GNU-FDL
@unnumbered GNU-FDL
@cindex license
@cindex GNU Free Documentation License
@include ../../common/texi/fdl-1.3.texi

@node Concept Index
@unnumbered Concept Index

@printindex cp

@bye