PHP code example of tcc / laravel-emdha-esign

1. Go to this page and download the library: Download tcc/laravel-emdha-esign library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

tcc / laravel-emdha-esign example snippets


use Tcc\EmdhaEsign\Facades\Emdha;
use Tcc\EmdhaEsign\DTO\SignerInfo;
use Tcc\EmdhaEsign\DTO\DocOptions;

// Read your PDF and base64-encode it
$docBase64 = base64_encode(file_get_contents(storage_path('app/documents/contract.pdf')));

// Define signer information
$signerInfo = new SignerInfo(
    kycId: '2515534888',
    englishName: 'Ahmed Al-Rashid',
    email: '[email protected]',
    arabicName: 'أحمد الراشد',
    mobile: '556654362',
);

// Define signing options
$docOptions = new DocOptions(
    reason: 'Contract Approval',
    location: 'Riyadh',
    signatureAppearanceType: 'emdhaLogo',
);

// Sign the document
$result = Emdha::signDocument($docBase64, $signerInfo, $docOptions);

if ($result->success) {
    // Save the signed PDF
    file_put_contents(storage_path('app/documents/signed_contract.pdf'), $result->getSignedPdf());
} else {
    // Handle error
    logger()->error('EMDHA signing failed', [
        'code' => $result->errorCode,
        'message' => $result->errorMessage,
    ]);
}

$result = Emdha::signDocument(
    string $docBase64,           // Base64-encoded PDF content
    SignerInfo $signerInfo,      // Signer identity information
    ?DocOptions $docOptions,    // Signing options (optional)
    ?string $transactionId,     // Custom transaction ID (optional, auto-generated if omitted)
): EmdhaSigningResult

$result = Emdha::signMultipleDocuments(
    array $docsBase64,           // Array of base64-encoded PDFs
    SignerInfo $signerInfo,      // Signer identity (shared across all docs)
    array $docOptionsList,       // Array of DocOptions arrays (one per doc)
    ?string $transactionId,     // Custom transaction ID (optional)
): EmdhaSigningResult

$txId = Emdha::generateTransactionId();

$signerInfo = new SignerInfo(
    kycId: '2515534888',        // Required — National ID / KYC ID
    englishName: 'Ahmed',       // Required — English name
    email: '[email protected]',    // Required — Email address
    arabicName: 'أحمد',        // Optional — Arabic name
    mobile: '556654362',       // Optional — Mobile number
    address: 'Riyadh',         // Optional — Street address
    regionProvince: 'Riyadh',  // Optional — Region/province
    country: 'SA',             // Optional — Country code (default: SA)
);

// Accepts both camelCase and snake_case keys
$signerInfo = SignerInfo::fromArray([
    'kycId' => '2515534888',
    // or 'national_id' => '2515534888',
    'englishName' => 'Ahmed',
    // or 'english_name' => 'Ahmed',
    'email' => '[email protected]',
]);

$docOptions = new DocOptions(
    reason: 'Document Signing',              // Signing reason
    location: 'Saudi Arabia',                // Signing location
    coordinates: 'bottomRight',              // Signature position on page
    pageTobeSigned: 'all',                   // Which page(s) to sign
    signatureAppearanceType: 'emdhaLogo',    // Appearance type
    appearanceContent: '',                   // Custom appearance text
    fontSize: 7,                             // Font size for appearance
    appearanceRunDirection: 'ltr',           // Text direction: 'ltr' or 'rtl'
    appearanceBackgroundImage: '',           // Base64 image for customLogo
    signatureImagePosition: 'leftOfText',    // Image position: 'leftOfText' or 'rightOfText'
    coSign: true,                            // Co-sign (append to existing sig)
);

$result->success;              // bool — whether signing succeeded
$result->signedPdfBase64;      // ?string — base64-encoded signed PDF (null on failure)
$result->errorCode;            // ?string — EMDHA error code (null on success)
$result->errorMessage;         // ?string — human-readable error message
$result->transactionId;        // ?string — transaction ID used
$result->requestXml;           // ?string — raw request XML sent to API
$result->responseXml;          // ?string — raw response XML from API

$result->getSignedPdf();       // ?string — decoded signed PDF binary (null on failure)
$result->getErrorDescription(); // string — full EMDHA error description

$docOptions = new DocOptions(signatureAppearanceType: 'noImage');

$docOptions = new DocOptions(signatureAppearanceType: 'emdhaLogo');

$signatureImageBase64 = base64_encode(file_get_contents(storage_path('app/signature.png')));

$docOptions = new DocOptions(
    signatureAppearanceType: 'customLogo',
    appearanceBackgroundImage: $signatureImageBase64,
    signatureImagePosition: 'rightOfText',
);

$docs = [
    base64_encode(file_get_contents(storage_path('app/docs/contract.pdf'))),
    base64_encode(file_get_contents(storage_path('app/docs/appendix.pdf'))),
];

$docOptionsList = [
    ['reason' => 'Contract Approval', 'coordinates' => 'bottomRight'],
    ['reason' => 'Appendix Approval', 'coordinates' => 'bottomLeft', 'signatureAppearanceType' => 'customLogo'],
];

$result = Emdha::signMultipleDocuments($docs, $signerInfo, $docOptionsList);

use Tcc\EmdhaEsign\Services\EmdhaErrorCode;

$message = EmdhaErrorCode::getMessage('ESIGN-1004');
// "Invalid SIP Access Key Hash — verify your PFX certificate..."

$allErrors = EmdhaErrorCode::getAllErrors();
// Returns the full error map as an array

$result = Emdha::signDocument($docBase64, $signerInfo, $docOptions);

if (!$result->success) {
    $errorCode = $result->errorCode;         // e.g., 'ESIGN-1004'
    $errorMessage = $result->errorMessage;    // e.g., 'Invalid SIP Access Key Hash'
    $fullDescription = $result->getErrorDescription(); // Full mapped description

    // Log or display the error
    Log::error('EMDHA signing failed', [
        'code' => $errorCode,
        'message' => $fullDescription,
        'transaction_id' => $result->transactionId,
    ]);
}

Schema::create('documents', function (Blueprint $table) {
    $table->id();
    $table->foreignId('user_id')->constrained()->cascadeOnDelete();
    $table->string('original_filename');
    $table->string('original_path');
    $table->string('signed_path')->nullable();
    $table->string('status')->default('pending');
    $table->string('transaction_id')->unique();
    $table->text('doc_base64')->nullable();
    $table->string('signed_by')->nullable();
    $table->json('signer_info')->nullable();
    $table->string('signature_image_path')->nullable();
    $table->timestamps();
});

use Tcc\EmdhaEsign\Facades\Emdha;
use Tcc\EmdhaEsign\DTO\SignerInfo;
use Tcc\EmdhaEsign\DTO\DocOptions;

class DocumentController extends Controller
{
    public function sign(Document $document, Request $request)
    {
        $signerInfo = new SignerInfo(
            kycId: $request->input('national_id'),
            englishName: $request->input('english_name'),
            email: $request->input('email'),
        );

        $docOptions = new DocOptions(
            reason: $request->input('reason', 'Document Signing'),
            signatureAppearanceType: $request->input('appearance_type', 'emdhaLogo'),
        );

        // Handle signature image for custom logo
        if ($request->hasFile('signature_image')) {
            $imageBase64 = base64_encode($request->file('signature_image')->getContent());
            $docOptions = new DocOptions(
                reason: $docOptions->reason,
                signatureAppearanceType: 'customLogo',
                appearanceBackgroundImage: $imageBase64,
            );
        }

        $result = Emdha::signDocument(
            $document->doc_base64,
            $signerInfo,
            $docOptions,
            $document->transaction_id
        );

        if ($result->success) {
            $signedPdf = $result->getSignedPdf();
            $signedPath = 'documents/signed/' . $document->transaction_id . '.pdf';
            Storage::put($signedPath, $signedPdf);

            $document->update([
                'status' => 'signed',
                'signed_path' => $signedPath,
                'signed_by' => $signerInfo->englishName,
            ]);

            return redirect()->back()->with('success', 'Document signed!');
        }

        return redirect()->back()->with('error', 'Signing failed: ' . $result->errorMessage);
    }
}

public function sign(Document $document, Request $request)
{
    $result = Emdha::signDocument(
        $document->doc_base64,
        SignerInfo::fromArray($request->input('signer_info')),
        DocOptions::fromArray($request->input('doc_options')),
    );

    if ($result->success) {
        Storage::put('signed/' . $document->transaction_id . '.pdf', $result->getSignedPdf());
        $document->update(['status' => 'signed']);
    }

    return redirect()->back()->with(
        $result->success ? 'success' : 'error',
        $result->success ? 'Signed!' : $result->errorMessage
    );
}

Route::middleware('auth:sanctum')->post('/documents/{document}/sign', function (Document $document, Request $request) {
    $result = Emdha::signDocument(
        $document->doc_base64,
        SignerInfo::fromArray($request->input('signer')),
        DocOptions::fromArray($request->input('options')),
    );

    if ($result->success) {
        Storage::put('signed/' . $document->transaction_id . '.pdf', $result->getSignedPdf());
        $document->update(['status' => 'signed']);
    }

    return response()->json([
        'success' => $result->success,
        'error_code' => $result->errorCode,
        'error_message' => $result->errorMessage,
        'transaction_id' => $result->transactionId,
    ]);
});
bash
php artisan vendor:publish --tag=emdha-config
bash
php artisan emdha:check