php|January 12, 2022|2 min read

Paypal Payment Issue While Validating Payment - Access Denied

TL;DR

The PayPal 'Access Denied' error on payment validation occurs when the validation endpoint URL changes; update the cgi-bin/webscr URL to the current PayPal endpoint.

Paypal Payment Issue While Validating Payment - Access Denied

Introduction

I was using Paypal payment on one of my website, and suddenly lot of complaints started coming that their payment is not reflected. The exact error that was coming is:

Access Denied.

You don't have permission to access "/cgi-bin/webscr" on this server.

Why Validation

Let me expand the scenario a bit more. When user initiate a payment, I redirect user to the Paypal website. When user do the payment, it calls my website URL with the payment details.

It is a best practice from security perspective to validate this payment from Paypal.

Old Code for Validation in Php

$req = 'cmd=_notify-validate';
if (function_exists('get_magic_quotes_gpc')) {
    $get_magic_quotes_exists = TRUE;
}
else {
    $get_magic_quotes_exists = FALSE;
}

foreach ($postVars as $key => $value) {
    if ($get_magic_quotes_exists == TRUE) {
        $value = urlencode(stripslashes($value));
    }
    else {
        $value = urlencode($value);
    }
    $req .= "&$key=$value";
}

$url = 'https://www.paypal.com/cgi-bin/webscr';

$ch = curl_init($url);
curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $req);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
curl_setopt($ch, CURLOPT_FORBID_REUSE, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Connection: Close'));

if (!($res = curl_exec($ch))) {
  //invalid response
  curl_close($ch);
  return;
}
curl_close($ch);

if (strcmp($res, "VERIFIED") == 0) {
    $txn_type = strtoupper($_POST['txn_type']);

    switch ($txn_type) {
        // A subscriber has signed up for the service.
        case 'SUBSCR_SIGNUP':
            //handle_call1($res)
            break;

        case 'SUBSCR_CANCEL': // A subscriber cancelled a subscription.
        case 'SUBSCR_MODIFY': // A subscriber profile has been modified.
        case 'SUBSCR_FAILED': // A subscriber tried to pay for the service but things didn't work out.
        case 'SUBSCR_EOT': // A subscriber has reached the end of the subscription term.
            //do nothing
            break;

        // A subscriber has paid for the service.
        case 'SUBSCR_PAYMENT':
        case 'WEB_ACCEPT':
            //handle_call2($res);
            break;
    }
}
else {
    if (strcmp($res, "INVALID") == 0) {
        //Invalid response returned from Paypal
        return;
    }
}

Lets Focus on the main code:

$ch = curl_init($url);
curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $req);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
curl_setopt($ch, CURLOPT_FORBID_REUSE, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Connection: Close'));

Working Earlier

This solution worked for years. Suddenly, without any information Paypal did change something at their side. And, it took lot of time for me to figure out. As, it was not expected from Paypal to implement the breaking changes.

And, the error was:

Access Denied.

You don't have permission to access "/cgi-bin/webscr" on this server.

The Solution

Paypal started accepting a User-Agent header, with your company name. I think, the company name must have minimum 5 characters.

The code now becomes:

$ch = curl_init($url);
curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $req);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
curl_setopt($ch, CURLOPT_FORBID_REUSE, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Connection: Close', 'User-Agent: mycompany'));

And, it worked finally. Poor show Paypal. Hope it helps.

Related Posts

Drupal 7: How to save a node programmatically and add an image field from a public URL

Drupal 7: How to save a node programmatically and add an image field from a public URL

Note: I have public URLs of these images, which I want to save. return…

How to get all image tags from an html - php code

How to get all image tags from an html - php code

I wanted to fetch all image tags from a big html, and wanted to perform some…

Drupal: How to block a user by email programatically

Drupal: How to block a user by email programatically

Many times, while administering your drupal website, you must have encountered…

How to connect Php docker container with Mongo DB docker container

How to connect Php docker container with Mongo DB docker container

Goto your command terminal. Type: This will expose port: 27017 by default. You…

How to install Mongo DB Driver for Php 7.x

How to install Mongo DB Driver for Php 7.x

The simplest way to install driver for php is using pecl. When I tried to run…

List all the Node ids which do not have images from my domain

List all the Node ids which do not have images from my domain

I use drupal-7 in my website. I used to write articles and put images in that…

Latest Posts

REST API Design: Pagination, Versioning, and Best Practices

REST API Design: Pagination, Versioning, and Best Practices

Every time two systems need to talk, someone has to design the contract between…

Efficient Data Modelling: A Practical Guide for Production Systems

Efficient Data Modelling: A Practical Guide for Production Systems

Most engineers learn data modelling backwards. They draw an ER diagram…

Deep Dive on Caching: From Browser to Database

Deep Dive on Caching: From Browser to Database

“There are only two hard things in Computer Science: cache invalidation and…

System Design Patterns for Real-Time Updates at High Traffic

System Design Patterns for Real-Time Updates at High Traffic

The previous articles in this series covered scaling reads and scaling writes…

System Design Patterns for Scaling Writes

System Design Patterns for Scaling Writes

In the companion article on scaling reads, we covered caching, replicas, and…

System Design Patterns for Managing Long-Running Tasks

System Design Patterns for Managing Long-Running Tasks

Introduction Some operations simply can’t finish in the time a user is willing…