webservco / paypal
A PHP component/library. Takes payment for an order through the PayPal REST API (Orders v2): create the order, send the customer to PayPal, then capture the payment.
Requires
- php: ^8.4
- nyholm/psr7: ^1
- psr/http-client: ^1
- psr/http-message: ^2
- symfony/http-client: ^6
- webservco/configuration: ^2
- webservco/data: ^2
- webservco/database: ^2
- webservco/log: ^2
Requires (Dev)
- pds/skeleton: ^1
- phan/phan: ^6
- php-parallel-lint/php-console-highlighter: ^1
- php-parallel-lint/php-parallel-lint: ^1
- phpmd/phpmd: ^3
- phpstan/phpstan: ^2
- phpstan/phpstan-deprecation-rules: ^2
- phpstan/phpstan-phpunit: ^2
- phpstan/phpstan-strict-rules: ^2
- phpunit/phpunit: ^13
- slevomat/coding-standard: ^8
- squizlabs/php_codesniffer: ^4
- vimeo/psalm: ^6
- webservco/coding-standards: ^2
- webservco/component-common: ^2
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
A PHP component/library. Please see webservco/sandbox for an example project using these types of components.
Takes payment for an order through the PayPal REST API (Orders v2): create the order, send the customer to PayPal, then capture the payment.
- Requires: PayPal REST API credentials, two database tables (below),
symfony/http-clientandnyholm/psr7(installed with this package) - Related:
webservco/configuration,webservco/database,webservco/log
Installation
composer require webservco/paypal
Usage
A working example is in public/payment/ (entry points) and src/example_implementation/ (logic). Copy both into your project and adjust the paths.
The flow:
pay.php?orderReference=Test1loads the order, creates a PayPal order and redirects the customer to PayPal.- PayPal sends the customer back to
return.php, which captures the payment, saves the status and redirects toPAYMENT_RESULT_LOCATION. - If the customer cancels, PayPal sends them to
PAYMENT_CANCEL_LOCATION.
languageCode is optional. If you pass it to pay.php, it's added to both the result and cancel URLs.
Contracts
| Interface | Implementation | Purpose |
|---|---|---|
Contract\Storage\Order\OrderPaymentStorageInterface |
Storage\Order\OrderPaymentStorage |
Reads the order total and status, and saves the payment result. |
| none | Storage\Payment\AccessTokenStorage |
Keeps the PayPal access token until it expires. |
| none | Payment\Paypal\Service\Authentication\AccessTokenService |
Gets an access token from PayPal. |
| none | Payment\Paypal\Service\Checkout\OrdersService |
Creates, reads and captures orders, and validates their status. |
Namespaces are relative to WebServCo\. If configuration isn't enough for your database, implement OrderPaymentStorageInterface yourself.
Configuration
Copy config/.env.development.ini to config/.env.ini and fill in the PayPal credentials. Table and field names can be changed to match an existing table.
[Payment system] ; The configuration key that holds the application URL. PAYMENT_APP_BASE_URL_SETTING_KEY = APP_URL ; Used when orders have no currency field. PAYMENT_DEFAULT_CURRENCY = EUR PAYMENT_FIELD_NAME_ORDER_REFERENCE = order_reference PAYMENT_FIELD_NAME_ORDER_TOTAL = order_total ; Leave empty if orders have no currency field. PAYMENT_FIELD_NAME_ORDER_CURRENCY = order_currency PAYMENT_FIELD_NAME_ORDER_PAYMENT_STATUS = order_payment_status PAYMENT_FIELD_NAME_PAYMENT_TIME = payment_event_date_time PAYMENT_TABLE_NAME_ORDERS = payment_order PAYMENT_TABLE_NAME_TOKEN = payment_access_token PAYMENT_CANCEL_LOCATION = payment-ko.html PAYMENT_RESULT_LOCATION = payment-finished.php [PayPal] PAYPAL_API_CLIENT_ID = PAYPAL_API_SECRET = ; No trailing slash. Production: https://api-m.paypal.com and https://www.paypal.com PAYPAL_API_BASE_URL = "https://api-m.sandbox.paypal.com" PAYPAL_WEB_BASE_URL = "https://www.sandbox.paypal.com"
The example also reads APP_URL and the DB_* keys (see webservco/database).
Tables
Add these fields to your orders table, or create a new one:
CREATE TABLE payment_order ( order_reference VARCHAR(45) NOT NULL, order_total DECIMAL(10,2) NOT NULL, -- Optional. PayPal currency codes: https://developer.paypal.com/reference/currency-codes/ order_currency CHAR(3) NOT NULL, order_payment_status VARCHAR(45) DEFAULT NULL, payment_event_date_time DATETIME DEFAULT NULL, PRIMARY KEY(order_reference) ) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci; CREATE TABLE payment_access_token ( token VARCHAR(100) NOT NULL, expire_date_time DATETIME NOT NULL, added_date_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY(token) ) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci;
Notes
Before copying the example
return.inc.php adds the PayPal access token to the result page URL (&accessToken=...). That puts the token in browser history and server logs. Remove it unless the result page needs it.
Both example scripts print the exception message on error. Show a generic message in production and keep the details in the log (var/log/, channel payment).
Trying the example
- Create
config/.env.iniwith sandbox credentials, then runddev startand create the tables. - Add a test order:
INSERT INTO payment_order (order_reference, order_total, order_currency) VALUES ('Test1', 123.45, 'EUR'); - Open
https://paypal.ddev.site/payment/pay.php?orderReference=Test1&languageCode=enand pay with a sandbox test card.
See also Get started with PayPal REST APIs.
Development
# Start project. ddev start # Install dependencies. ddev c u # Run all validations. ddev c c # Run unit tests. ddev c test:dox