diff --git a/composer.lock b/composer.lock
index aa8773a..1d2867f 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,25 +4,25 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "0934509931d20fd913f0862cd8aaeea7",
+ "content-hash": "fde257651cc530ab11eff5a843283379",
"packages": [
{
"name": "psr/http-client",
- "version": "1.0.1",
+ "version": "1.0.2",
"source": {
"type": "git",
"url": "https://github.com/php-fig/http-client.git",
- "reference": "2dfb5f6c5eff0e91e20e913f8c5452ed95b86621"
+ "reference": "0955afe48220520692d2d09f7ab7e0f93ffd6a31"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/php-fig/http-client/zipball/2dfb5f6c5eff0e91e20e913f8c5452ed95b86621",
- "reference": "2dfb5f6c5eff0e91e20e913f8c5452ed95b86621",
+ "url": "https://api.github.com/repos/php-fig/http-client/zipball/0955afe48220520692d2d09f7ab7e0f93ffd6a31",
+ "reference": "0955afe48220520692d2d09f7ab7e0f93ffd6a31",
"shasum": ""
},
"require": {
"php": "^7.0 || ^8.0",
- "psr/http-message": "^1.0"
+ "psr/http-message": "^1.0 || ^2.0"
},
"type": "library",
"extra": {
@@ -42,7 +42,7 @@
"authors": [
{
"name": "PHP-FIG",
- "homepage": "http://www.php-fig.org/"
+ "homepage": "https://www.php-fig.org/"
}
],
"description": "Common interface for HTTP clients",
@@ -54,27 +54,27 @@
"psr-18"
],
"support": {
- "source": "https://github.com/php-fig/http-client/tree/master"
+ "source": "https://github.com/php-fig/http-client/tree/1.0.2"
},
- "time": "2020-06-29T06:28:15+00:00"
+ "time": "2023-04-10T20:12:12+00:00"
},
{
"name": "psr/http-factory",
- "version": "1.0.1",
+ "version": "1.0.2",
"source": {
"type": "git",
"url": "https://github.com/php-fig/http-factory.git",
- "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be"
+ "reference": "e616d01114759c4c489f93b099585439f795fe35"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/php-fig/http-factory/zipball/12ac7fcd07e5b077433f5f2bee95b3a771bf61be",
- "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be",
+ "url": "https://api.github.com/repos/php-fig/http-factory/zipball/e616d01114759c4c489f93b099585439f795fe35",
+ "reference": "e616d01114759c4c489f93b099585439f795fe35",
"shasum": ""
},
"require": {
"php": ">=7.0.0",
- "psr/http-message": "^1.0"
+ "psr/http-message": "^1.0 || ^2.0"
},
"type": "library",
"extra": {
@@ -94,7 +94,7 @@
"authors": [
{
"name": "PHP-FIG",
- "homepage": "http://www.php-fig.org/"
+ "homepage": "https://www.php-fig.org/"
}
],
"description": "Common interfaces for PSR-7 HTTP message factories",
@@ -109,31 +109,31 @@
"response"
],
"support": {
- "source": "https://github.com/php-fig/http-factory/tree/master"
+ "source": "https://github.com/php-fig/http-factory/tree/1.0.2"
},
- "time": "2019-04-30T12:38:16+00:00"
+ "time": "2023-04-10T20:10:41+00:00"
},
{
"name": "psr/http-message",
- "version": "1.0.1",
+ "version": "1.1",
"source": {
"type": "git",
"url": "https://github.com/php-fig/http-message.git",
- "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363"
+ "reference": "cb6ce4845ce34a8ad9e68117c10ee90a29919eba"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363",
- "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363",
+ "url": "https://api.github.com/repos/php-fig/http-message/zipball/cb6ce4845ce34a8ad9e68117c10ee90a29919eba",
+ "reference": "cb6ce4845ce34a8ad9e68117c10ee90a29919eba",
"shasum": ""
},
"require": {
- "php": ">=5.3.0"
+ "php": "^7.2 || ^8.0"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "1.0.x-dev"
+ "dev-master": "1.1.x-dev"
}
},
"autoload": {
@@ -162,9 +162,9 @@
"response"
],
"support": {
- "source": "https://github.com/php-fig/http-message/tree/master"
+ "source": "https://github.com/php-fig/http-message/tree/1.1"
},
- "time": "2016-08-06T14:39:51+00:00"
+ "time": "2023-04-04T09:50:52+00:00"
},
{
"name": "setasign/setapdf-core",
@@ -414,16 +414,16 @@
},
{
"name": "guzzlehttp/psr7",
- "version": "1.9.0",
+ "version": "1.9.1",
"source": {
"type": "git",
"url": "https://github.com/guzzle/psr7.git",
- "reference": "e98e3e6d4f86621a9b75f623996e6bbdeb4b9318"
+ "reference": "e4490cabc77465aaee90b20cfc9a770f8c04be6b"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/guzzle/psr7/zipball/e98e3e6d4f86621a9b75f623996e6bbdeb4b9318",
- "reference": "e98e3e6d4f86621a9b75f623996e6bbdeb4b9318",
+ "url": "https://api.github.com/repos/guzzle/psr7/zipball/e4490cabc77465aaee90b20cfc9a770f8c04be6b",
+ "reference": "e4490cabc77465aaee90b20cfc9a770f8c04be6b",
"shasum": ""
},
"require": {
@@ -442,11 +442,6 @@
"laminas/laminas-httphandlerrunner": "Emit PSR-7 responses"
},
"type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "1.9-dev"
- }
- },
"autoload": {
"files": [
"src/functions_include.php"
@@ -504,7 +499,7 @@
],
"support": {
"issues": "https://github.com/guzzle/psr7/issues",
- "source": "https://github.com/guzzle/psr7/tree/1.9.0"
+ "source": "https://github.com/guzzle/psr7/tree/1.9.1"
},
"funding": [
{
@@ -520,24 +515,25 @@
"type": "tidelift"
}
],
- "time": "2022-06-20T21:43:03+00:00"
+ "time": "2023-04-17T16:00:37+00:00"
},
{
"name": "http-interop/http-factory-guzzle",
- "version": "1.1.1",
+ "version": "1.2.0",
"source": {
"type": "git",
"url": "https://github.com/http-interop/http-factory-guzzle.git",
- "reference": "6e1efa1e020bf1c47cf0f13654e8ef9efb1463b3"
+ "reference": "8f06e92b95405216b237521cc64c804dd44c4a81"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/http-interop/http-factory-guzzle/zipball/6e1efa1e020bf1c47cf0f13654e8ef9efb1463b3",
- "reference": "6e1efa1e020bf1c47cf0f13654e8ef9efb1463b3",
+ "url": "https://api.github.com/repos/http-interop/http-factory-guzzle/zipball/8f06e92b95405216b237521cc64c804dd44c4a81",
+ "reference": "8f06e92b95405216b237521cc64c804dd44c4a81",
"shasum": ""
},
"require": {
- "guzzlehttp/psr7": "^1.4.2||^2.0",
+ "guzzlehttp/psr7": "^1.7||^2.0",
+ "php": ">=7.3",
"psr/http-factory": "^1.0"
},
"provide": {
@@ -545,7 +541,10 @@
},
"require-dev": {
"http-interop/http-factory-tests": "^0.9",
- "phpunit/phpunit": "^8.5"
+ "phpunit/phpunit": "^9.5"
+ },
+ "suggest": {
+ "guzzlehttp/psr7": "Includes an HTTP factory starting in version 2.0"
},
"type": "library",
"autoload": {
@@ -572,22 +571,22 @@
],
"support": {
"issues": "https://github.com/http-interop/http-factory-guzzle/issues",
- "source": "https://github.com/http-interop/http-factory-guzzle/tree/1.1.1"
+ "source": "https://github.com/http-interop/http-factory-guzzle/tree/1.2.0"
},
- "time": "2021-07-23T15:14:50+00:00"
+ "time": "2021-07-21T13:50:14+00:00"
},
{
"name": "league/oauth2-client",
- "version": "2.6.1",
+ "version": "2.7.0",
"source": {
"type": "git",
"url": "https://github.com/thephpleague/oauth2-client.git",
- "reference": "2334c249907190c132364f5dae0287ab8666aa19"
+ "reference": "160d6274b03562ebeb55ed18399281d8118b76c8"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/thephpleague/oauth2-client/zipball/2334c249907190c132364f5dae0287ab8666aa19",
- "reference": "2334c249907190c132364f5dae0287ab8666aa19",
+ "url": "https://api.github.com/repos/thephpleague/oauth2-client/zipball/160d6274b03562ebeb55ed18399281d8118b76c8",
+ "reference": "160d6274b03562ebeb55ed18399281d8118b76c8",
"shasum": ""
},
"require": {
@@ -642,9 +641,9 @@
],
"support": {
"issues": "https://github.com/thephpleague/oauth2-client/issues",
- "source": "https://github.com/thephpleague/oauth2-client/tree/2.6.1"
+ "source": "https://github.com/thephpleague/oauth2-client/tree/2.7.0"
},
- "time": "2021-12-22T16:42:49+00:00"
+ "time": "2023-04-16T18:19:15+00:00"
},
{
"name": "mjelamanov/psr18-guzzle",
@@ -1162,5 +1161,5 @@
"ext-json": "*"
},
"platform-dev": [],
- "plugin-api-version": "2.2.0"
+ "plugin-api-version": "2.3.0"
}
diff --git a/examples/appearance-demo.php b/examples/appearance-demo.php
index 2ff2fad..4bb3240 100644
--- a/examples/appearance-demo.php
+++ b/examples/appearance-demo.php
@@ -3,6 +3,7 @@
declare(strict_types=1);
use setasign\SetaPDF\Signer\Module\CSC\Client;
+use setasign\SetaPDF\Signer\Module\CSC\ClientException;
use setasign\SetaPDF\Signer\Module\CSC\Module;
ini_set('display_errors', '1');
@@ -108,7 +109,19 @@
$appearance = new SetaPDF_Signer_Signature_Appearance_Dynamic($module);
$signer->setAppearance($appearance);
-$signer->sign($module);
+try {
+ $signer->sign($module);
+} catch (ClientException $e) {
+ echo 'An error occured:';
+ echo $e->getMessage() . ': ' . $e->getResponse()->getBody();
+ echo '
restart';
+ die();
+} catch (\Exception $e) {
+ echo 'An error occured:';
+ echo $e->getMessage();
+ echo '
restart';
+ die();
+}
echo 'download | restart
';
diff --git a/examples/assets/SSL.com.dev-ca.cer b/examples/assets/SSL.com.dev-ca.cer
new file mode 100644
index 0000000..3b145b7
Binary files /dev/null and b/examples/assets/SSL.com.dev-ca.cer differ
diff --git a/examples/async-demo.php b/examples/async-demo.php
index 49a5de5..ae2814a 100644
--- a/examples/async-demo.php
+++ b/examples/async-demo.php
@@ -2,6 +2,8 @@
declare(strict_types=1);
+use League\OAuth2\Client\OptionProvider\OptionProviderInterface;
+use League\OAuth2\Client\Provider\AbstractProvider;
use League\OAuth2\Client\Provider\GenericProvider;
use SetaPDF_Signer_Digest as Digest;
use setasign\SetaPDF\Signer\Module\CSC\Client;
@@ -26,7 +28,7 @@
$settings = require 'settings.php';
$apiUri = $settings['apiUri'];
-$fileToSign = __DIR__ . '/Laboratory-Report.pdf';
+$fileToSign = __DIR__ . '/assets/Laboratory-Report.pdf';
$resultPath = 'signed.pdf';
@@ -56,7 +58,23 @@
'urlAuthorize' => $oauth2Urls['urlAuthorize'],
'urlAccessToken' => $oauth2Urls['urlAccessToken'],
'urlResourceOwnerDetails' => $oauth2Urls['urlResourceOwnerDetails'],
-]);
+] /*
+ // If your OAuth endpoint requires a JSON document instead of a form-encoded document pass following "optionProvider"
+ // to the GenericProvider constructor:
+ , [
+ 'optionProvider' => new class implements OptionProviderInterface {
+ public function getAccessTokenOptions($method, array $params)
+ {
+ $options = ['headers' => ['content-type' => 'application/json']];
+
+ if ($method === AbstractProvider::METHOD_POST) {
+ $options['body'] = json_encode($params);
+ }
+
+ return $options;
+ }
+ }
+]*/);
$action = $_GET['action'] ?? 'preview';
// if the oauth request was unsuccessful, return to preSign
diff --git a/examples/demo.php b/examples/demo.php
index dad294b..ff2a8cd 100644
--- a/examples/demo.php
+++ b/examples/demo.php
@@ -3,6 +3,7 @@
declare(strict_types=1);
use setasign\SetaPDF\Signer\Module\CSC\Client;
+use setasign\SetaPDF\Signer\Module\CSC\ClientException;
use setasign\SetaPDF\Signer\Module\CSC\Module;
ini_set('display_errors', '1');
@@ -93,8 +94,19 @@
// create the signer instance
$signer = new SetaPDF_Signer($document);
-
-$signer->sign($module);
+try {
+ $signer->sign($module);
+} catch (ClientException $e) {
+ echo 'An error occured:';
+ echo $e->getMessage() . ': ' . $e->getResponse()->getBody();
+ echo '
restart';
+ die();
+} catch (\Exception $e) {
+ echo 'An error occured:';
+ echo $e->getMessage();
+ echo '
restart';
+ die();
+}
echo 'download | restart
';
diff --git a/examples/generate-token.php b/examples/generate-token.php
index e06544c..f413c68 100644
--- a/examples/generate-token.php
+++ b/examples/generate-token.php
@@ -1,5 +1,7 @@
$oauth2Urls['urlAuthorize'],
'urlAccessToken' => $oauth2Urls['urlAccessToken'],
'urlResourceOwnerDetails' => $oauth2Urls['urlResourceOwnerDetails'],
-]);
+]
+/*
+ // If your OAuth endpoint requires a JSON document instead of a form-encoded document pass following "optionProvider"
+ // to the GenericProvider constructor:
+ , [
+ 'optionProvider' => new class implements OptionProviderInterface {
+ public function getAccessTokenOptions($method, array $params)
+ {
+ $options = ['headers' => ['content-type' => 'application/json']];
+
+ if ($method === AbstractProvider::METHOD_POST) {
+ $options['body'] = json_encode($params);
+ }
+
+ return $options;
+ }
+ }
+]*/
+);
session_start();
diff --git a/examples/ltv-demo.php b/examples/ltv-demo.php
index 5af12b6..92badee 100644
--- a/examples/ltv-demo.php
+++ b/examples/ltv-demo.php
@@ -3,6 +3,7 @@
declare(strict_types=1);
use setasign\SetaPDF\Signer\Module\CSC\Client;
+use setasign\SetaPDF\Signer\Module\CSC\ClientException;
use setasign\SetaPDF\Signer\Module\CSC\Module;
ini_set('display_errors', '1');
@@ -26,6 +27,7 @@
$timestampingUrl = 'http://ts.ssl.com';
$trustedCertificatesPath = __DIR__ . '/assets/SSL.com.ca-bundle';
+$otherTrustedCertificatePaths = [__DIR__ . '/assets/SSL.com.dev-ca.cer'];
// to create or update your access token you have to call generate-token.php first
if (!isset($_SESSION['accessToken']['access_token'])) {
@@ -82,6 +84,11 @@
// create a collection of trusted certificats:
$trustedCertificates = new SetaPDF_Signer_X509_Collection($certificates[count($certificates) - 1]);
$trustedCertificates->add(SetaPDF_Signer_Pem::extractFromFile($trustedCertificatesPath));
+// sadly not all CSC API implementations return the full chain (in our tests e.g. SSL.com), so we have to
+// add a trusted root on our own:
+foreach ($otherTrustedCertificatePaths as $otherTrustedCertificatePath) {
+ $trustedCertificates->addFromFile($otherTrustedCertificatePath);
+}
// create a collector instance
$collector = new SetaPDF_Signer_ValidationRelatedInfo_Collector($trustedCertificates);
@@ -128,7 +135,19 @@
// ...this is needed to add validation related information later
$signer->setSignatureFieldName($signatureField->getQualifiedName());
-$signer->sign($module);
+try {
+ $signer->sign($module);
+} catch (ClientException $e) {
+ echo 'An error occured:';
+ echo $e->getMessage() . ': ' . $e->getResponse()->getBody();
+ echo '
restart';
+ die();
+} catch (\Exception $e) {
+ echo 'An error occured:';
+ echo $e->getMessage();
+ echo '
restart';
+ die();
+}
// create a new instance
$document = SetaPDF_Core_Document::loadByFilename($tmpWriter->getPath(), $writer);
diff --git a/src/Client.php b/src/Client.php
index 41e21c7..98f0d1b 100644
--- a/src/Client.php
+++ b/src/Client.php
@@ -5,7 +5,6 @@
namespace setasign\SetaPDF\Signer\Module\CSC;
use BadMethodCallException;
-use Exception;
use Psr\Http\Client\ClientExceptionInterface;
use Psr\Http\Client\ClientInterface;
use Psr\Http\Message\RequestFactoryInterface;
@@ -98,7 +97,7 @@ public function getOauth2Info(): array
* @param int $depth
* @param int $options
* @return mixed
- * @throws Exception
+ * @throws ClientException
*/
protected function json_decode(string $json, bool $assoc = true, int $depth = 512, int $options = 0)
{
@@ -108,7 +107,7 @@ protected function json_decode(string $json, bool $assoc = true, int $depth = 51
$data = @\json_decode($json, $assoc, $depth, $options);
if (\json_last_error() !== JSON_ERROR_NONE) {
- throw new Exception(\sprintf(
+ throw new \InvalidArgumentException(\sprintf(
'Unable to decode JSON: %s',
\json_last_error_msg()
));
@@ -123,7 +122,7 @@ protected function json_decode(string $json, bool $assoc = true, int $depth = 51
* @param array $inputData
* @return array
* @throws ClientExceptionInterface
- * @throws Exception
+ * @throws ClientException
*/
public function call(string $path, ?string $accessToken = null, array $inputData = []): array
{
@@ -144,7 +143,8 @@ public function call(string $path, ?string $accessToken = null, array $inputData
$response = $this->httpClient->sendRequest($request);
if ($response->getStatusCode() !== 200) {
- throw new Exception('Error on ' . $path . ': ' . $response->getBody());
+ // $body in the message is kept for BC, don't rely on it but use $e->getData() instead!
+ throw new ClientException('Error on ' . $path . ': ' . $response->getBody(), $response);
}
return $this->json_decode((string) $response->getBody());
@@ -183,7 +183,7 @@ public function info(?string $lang = null): array
* @param string|null $pageToken
* @param string|null $clientData
* @return array
- * @throws ClientExceptionInterface
+ * @throws ClientExceptionInterface|ClientException
* @see CSC API 11.4 /credentials/list
*/
public function credentialsList(
@@ -222,7 +222,7 @@ public function credentialsList(
* @param string|null $lang
* @param string|null $clientData
* @return array
- * @throws ClientExceptionInterface
+ * @throws ClientExceptionInterface|ClientException
* @see CSC API 11.5 /credentials/info
*/
public function credentialsInfo(
@@ -268,7 +268,7 @@ public function credentialsInfo(
* @param string $credentialID
* @param string|null $clientData
* @return array
- * @throws ClientExceptionInterface
+ * @throws ClientExceptionInterface|ClientException
* @see CSC API 11.8 /credentials/sendOTP
*/
public function credentialsSendOTP(string $accessToken, string $credentialID, ?string $clientData = null): array
@@ -297,7 +297,7 @@ public function credentialsSendOTP(string $accessToken, string $credentialID, ?s
* @param string|null $description
* @param string|null $clientData
* @return array
- * @throws ClientExceptionInterface
+ * @throws ClientExceptionInterface|ClientException
* @see CSC API 11.6 /credentials/authorize
*/
public function credentialsAuthorize(
@@ -343,7 +343,7 @@ public function credentialsAuthorize(
* @param string|null $signAlgoParams
* @param string|null $clientData
* @return array
- * @throws ClientExceptionInterface
+ * @throws ClientExceptionInterface|ClientException
* @see CSC API 11.9 /signatures/signHash
*/
public function signaturesSignHash(
diff --git a/src/ClientException.php b/src/ClientException.php
new file mode 100644
index 0000000..ad3fb88
--- /dev/null
+++ b/src/ClientException.php
@@ -0,0 +1,30 @@
+response = $response;
+ }
+
+ public function getResponse()
+ {
+ return $this->response;
+ }
+}
diff --git a/src/Exception.php b/src/Exception.php
deleted file mode 100644
index fbd3f79..0000000
--- a/src/Exception.php
+++ /dev/null
@@ -1,15 +0,0 @@
-