Issues (87)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

code/PayPalExpressCheckoutPayment.php (85 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
0 ignored issues
show
File has mixed line endings; this may cause incorrect results
Loading history...
2
3
/**
4
 * PayPal Express Checkout Payment
5
 * @author Jeremy Shipman jeremy [at] burnbright.net
6
 * @author Nicolaas [at] sunnysideup.co.nz
7
 *
8
 * Developer documentation:
9
 * Integration guide: https://cms.paypal.com/cms_content/US/en_US/files/developer/PP_ExpressCheckout_IntegrationGuide.pdf
10
 * API reference: 	  https://cms.paypal.com/us/cgi-bin/?cmd=_render-content&content_ID=developer/howto_api_reference
11
 * Uses the Name-Value Pair API protocol
12
 *
13
 */
14
15
16
17
class PayPalExpressCheckoutPayment extends EcommercePayment
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
18
{
19
    private static $debug = false;
0 ignored issues
show
The property $debug is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
20
21
    private static $db = array(
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
22
        'Token' => 'Varchar(30)',
23
        'PayerID' => 'Varchar(30)',
24
        'TransactionID' => 'Varchar(30)',
25
        'AuthorisationCode' => 'Text',
26
        'Debug' => 'HTMLText'
27
    );
28
    private static $logo = "ecommerce/images/paymentmethods/paypal.jpg";
0 ignored issues
show
The property $logo is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
29
    private static $payment_methods = array();
0 ignored issues
show
The property $payment_methods is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
30
31
    //PayPal URLs
32
    private static $test_API_Endpoint = "https://api-3t.sandbox.paypal.com/nvp";
0 ignored issues
show
The property $test_API_Endpoint is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
33
    private static $test_PAYPAL_URL = "https://www.sandbox.paypal.com/webscr?cmd=_express-checkout&token=";
0 ignored issues
show
The property $test_PAYPAL_URL is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
34
    private static $API_Endpoint = "https://api-3t.paypal.com/nvp";
0 ignored issues
show
The property $API_Endpoint is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
35
    private static $PAYPAL_URL = "https://www.paypal.com/cgi-bin/webscr?cmd=_express-checkout&token=";
0 ignored issues
show
The property $PAYPAL_URL is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
36
    private static $privacy_link = "https://www.paypal.com/us/cgi-bin/webscr?cmd=p/gen/ua/policy_privacy-outside";
0 ignored issues
show
The property $privacy_link is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
37
38
    //config
39
    private static $test_mode = true; //on by default
0 ignored issues
show
The property $test_mode is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
40
    private static $API_UserName;
0 ignored issues
show
The property $API_UserName is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
41
    private static $API_Password;
0 ignored issues
show
The property $API_Password is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
42
    private static $API_Signature;
0 ignored issues
show
The property $API_Signature is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
43
    private static $sBNCode = null; // BN Code 	is only applicable for partners
0 ignored issues
show
The property $sBNCode is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
44
    private static $version = '64';
0 ignored issues
show
The property $version is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
45
46
    //set custom settings
47
    private static $custom_settings = array(
0 ignored issues
show
The property $custom_settings is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
48
        //design
49
        //'HDRIMG' => "http://www.mysite.com/images/logo.jpg", //max size = 750px wide by 90px high, and good to be on secure server
0 ignored issues
show
Unused Code Comprehensibility introduced by
58% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
50
        //'HDRBORDERCOLOR' => 'CCCCCC', //header border
0 ignored issues
show
Unused Code Comprehensibility introduced by
58% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
51
        //'HDRBACKCOLOR' => '00FFFF', //header background
0 ignored issues
show
Unused Code Comprehensibility introduced by
58% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
52
        //'PAYFLOWCOLOR'=> 'AAAAAA' //payflow colour
53
        //'PAGESTYLE' => //page style set in merchant account settings
54
        'SOLUTIONTYPE' => 'Sole'//require paypal account, or not. Can be or 'Mark' (required) or 'Sole' (not required)
55
        //'BRANDNAME'  => 'my site name'//override business name in checkout
56
        //'CUSTOMERSERVICENUMBER' => '0800 1234 5689'//number to call to resolve payment issues
57
        //'NOSHIPPING' => 1 //disable showing shipping details
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
58
    );
59
60
    public function getCMSFields()
61
    {
62
        $fields = parent::getCMSFields();
63
        foreach (array_keys(self::$db) as $field) {
64
            $fields->removeFieldFromTab('Root.Main', $field);
65
            $fields->addFieldToTab('Root.Advanced', LiteralField::create($field.'_debug', '<h2>'.$field.'</h2><pre>'.$this->$field.'</pre>'));
66
        }
67
        return $fields;
68
    }
69
70
    public function getPaymentFormFields()
71
    {
72
        $logo = '<img src="' . $this->Config()->get("logo") . '" alt="Credit card payments powered by PayPal"/>';
73
        $privacyLink = '<a href="' . $this->Config()->get("privacy_link") . '" target="_blank" title="Read PayPal\'s privacy policy">' . $logo . '</a><br/>';
74
        return new FieldList(
75
            new LiteralField('PayPalInfo', $privacyLink),
76
            new LiteralField(
77
                'PayPalPaymentsList',
78
                $this->renderWith("PaymentMethods")
79
            )
80
        );
81
    }
82
83
    public function getPaymentFormRequirements()
84
    {
85
        return null;
86
    }
87
88
    //main processing function
89
    public function processPayment($data, $form)
90
    {
91
        //sanity checks for credentials
92
        if (!$this->Config()->get("API_UserName") || !$this->Config()->get("API_Password") || !$this->Config()->get("API_Signature")) {
93
            user_error('You are attempting to make a payment without the necessary credentials set', E_USER_ERROR);
94
        }
95
        $data = $this->Order()->BillingAddress()->toMap();
0 ignored issues
show
Documentation Bug introduced by
The method Order does not exist on object<PayPalExpressCheckoutPayment>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
96
        $paymenturl = $this->getTokenURL($this->Amount->Amount, $this->Amount->Currency, $data);
0 ignored issues
show
The property Amount does not exist on object<PayPalExpressCheckoutPayment>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
97
        $this->Status = "Incomplete";
0 ignored issues
show
The property Status does not exist on object<PayPalExpressCheckoutPayment>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
98
        $this->write();
99
        if ($paymenturl) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $paymenturl of type null|string is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
100
            Controller::curr()->redirect($paymenturl); //redirect to payment gateway
101
            return EcommercePayment_Processing::create();
102
        }
103
        $this->Message = _t('PayPalExpressCheckoutPayment.COULDNOTBECONTACTED', "PayPal could not be contacted");
0 ignored issues
show
The property Message does not exist on object<PayPalExpressCheckoutPayment>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
104
        $this->Status = 'Failure';
0 ignored issues
show
The property Status does not exist on object<PayPalExpressCheckoutPayment>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
105
        $this->write();
106
        return EcommercePayment_Failure::create($this->Message);
0 ignored issues
show
The property Message does not exist on object<PayPalExpressCheckoutPayment>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
107
    }
108
109
    /**
110
     *
111
     * depracated
112
     */
113
    public function PayPalForm()
0 ignored issues
show
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
114
    {
115
        user_error("This form is no longer used.");
116
        Requirements::javascript(THIRDPARTY_DIR . '/jquery/jquery.js');
117
118
        // 1) Main Information
119
        $fields = '';
120
        $order = $this->Order();
0 ignored issues
show
Documentation Bug introduced by
The method Order does not exist on object<PayPalExpressCheckoutPayment>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
121
        $items = $order->Items();
122
        $member = $order->Member();
123
124
        // 2) Main Settings
125
126
        $url = $this->Config()->get("test_mode") ? $this->Config()->get("test_url") : $this->Config()->get("url");
127
        $inputs['cmd'] = '_cart';
0 ignored issues
show
Coding Style Comprehensibility introduced by
$inputs was never initialized. Although not strictly required by PHP, it is generally a good practice to add $inputs = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
128
        $inputs['upload'] = '1';
129
130
        // 3) Items Informations
131
132
        $cpt = 0;
133
        foreach ($items as $item) {
134
            $inputs['item_name_' . ++$cpt] = $item->TableTitle();
135
            // item_number is unnecessary
136
            $inputs['amount_' . $cpt] = $item->UnitPrice();
137
            $inputs['quantity_' . $cpt] = $item->Quantity;
138
        }
139
140
        // 4) Payment Informations And Authorisation Code
141
142
        $inputs['business'] = $this->Config()->get("test_mode") ? $this->Config()->get("test_account_email") : $this->Config()->get("account_email");
143
        $inputs['custom'] = $this->ID . '-' . $this->AuthorisationCode;
0 ignored issues
show
The property AuthorisationCode does not exist on object<PayPalExpressCheckoutPayment>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
144
        // Add Here The Shipping And/Or Taxes
145
        $inputs['currency_code'] = $this->Currency;
0 ignored issues
show
The property Currency does not exist on object<PayPalExpressCheckoutPayment>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
146
147
        // 5) Redirection Informations
148
149
        $inputs['cancel_return'] = Director::absoluteBaseURL() . PayPalExpressCheckoutPayment_Handler::cancel_link($inputs['custom']);
0 ignored issues
show
The call to PayPalExpressCheckoutPay..._Handler::cancel_link() has too many arguments starting with $inputs['custom'].

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
150
        $inputs['return'] = Director::absoluteBaseURL() . PayPalExpressCheckoutPayment_Handler::complete_link();
0 ignored issues
show
The method complete_link() does not seem to exist on object<PayPalExpressCheckoutPayment_Handler>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
151
        $inputs['rm'] = '2';
152
        // Add Here The Notify URL
153
154
        // 6) PayPal Pages Style Optional Informations
155
156
        if (self:: $continue_button_text) {
157
            $inputs['cbt'] = $this->Config()->get("continue_button_text");
158
        }
159
160
        if ($this->Config()->get("header_image_url")) {
161
            $inputs['cpp_header_image'] = urlencode($this->Config()->get("header_image_url"));
162
        }
163
        if ($this->Config()->get("header_back_color")) {
164
            $inputs['cpp_headerback_color'] = $this->Config()->get("header_back_color");
165
        }
166
        if ($this->Config()->get("header_border_color")) {
167
            $inputs['cpp_headerborder_color'] = $this->Config()->get("header_border_color");
168
        }
169
        if ($this->Config()->get("payflow_color")) {
170
            $inputs['cpp_payflow_color'] = $this->Config()->get("payflow_color");
171
        }
172
        if ($this->Config()->get("back_color")) {
173
            $inputs['cs'] = $this->Config()->get("back_color");
174
        }
175
        if ($this->Config()->get("image_url")) {
176
            $inputs['image_url'] = urlencode($this->Config()->get("image_url"));
177
        }
178
        if ($this->Config()->get("page_style")) {
179
            $inputs['page_style'] = $this->Config()->get("page_style");
180
        }
181
182
        // 7) Prepopulating Customer Informations
183
        $billingAddress = $order->BillingAddress();
184
        $inputs['first_name'] = $billingAddress->FirstName;
185
        $inputs['last_name'] = $billingAddress->Surname;
186
        $inputs['address1'] = $billingAddress->Address;
187
        $inputs['address2'] = $billingAddress->Address2;
188
        $inputs['city'] = $billingAddress->City;
189
        $inputs['zip'] = $billingAddress->PostalCode;
190
        $inputs['state'] = $billingAddress->Region()->Code;
191
        $inputs['country'] = $billingAddress->Country;
192
        $inputs['email'] = $member->Email;
193
194
        // 8) Form Creation
195
        if (is_array($inputs) && count($inputs)) {
196
            foreach ($inputs as $name => $value) {
197
                $ATT_value = Convert::raw2att($value);
198
                $fields .= "<input type=\"hidden\" name=\"$name\" value=\"$ATT_value\" />";
199
            }
200
        }
201
202
        return <<<HTML
203
            <form id="PaymentForm" method="post" action="$url">
204
                $fields
205
                <input type="submit" value="Submit" />
206
            </form>
207
            <script type="text/javascript">
208
                jQuery(document).ready(function() {
209
                    jQuery("input[type='submit']").hide();
210
                    jQuery('#PaymentForm').submit();
211
                });
212
            </script>
213
HTML;
214
    }
215
216
    public function populateDefaults()
217
    {
218
        parent::populateDefaults();
219
        $this->AuthorisationCode = md5(uniqid(rand(), true));
0 ignored issues
show
The property AuthorisationCode does not exist on object<PayPalExpressCheckoutPayment>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
220
    }
221
222
223
224
225
    /**
226
     * Requests a Token url, based on the provided Name-Value-Pair fields
227
     * See docs for more detail on these fields:
228
     * https://cms.paypal.com/us/cgi-bin/?cmd=_render-content&content_ID=developer/e_howto_api_nvp_r_SetExpressCheckout
229
     *
230
     * Note: some of these values will override the paypal merchant account settings.
231
     * Note: not all fields are listed here.
232
     */
233
    protected function getTokenURL($paymentAmount, $currencyCodeType, $extradata = array())
234
    {
235
        $data = array(
236
            //payment info
237
            'PAYMENTREQUEST_0_AMT' => $paymentAmount,
238
            'PAYMENTREQUEST_0_CURRENCYCODE' => $currencyCodeType, //TODO: check to be sure all currency codes match the SS ones
239
            //TODO: include individual costs: shipping, shipping discount, insurance, handling, tax??
240
            //'PAYMENTREQUEST_0_ITEMAMT' => //item(s)
241
            //'PAYMENTREQUEST_0_SHIPPINGAMT' //shipping
242
            //'PAYMENTREQUEST_0_SHIPDISCAMT' //shipping discount
243
            //'PAYMENTREQUEST_0_HANDLINGAMT' //handling
244
            //'PAYMENTREQUEST_0_TAXAMT' //tax
245
            //'PAYMENTREQUEST_0_INVNUM' => $this->PaidObjectID //invoice number
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
246
            //'PAYMENTREQUEST_0_TRANSACTIONID' //Transaction id
247
            //'PAYMENTREQUEST_0_DESC' => //description
248
            //'PAYMENTREQUEST_0_NOTETEXT' => //note to merchant
249
            //'PAYMENTREQUEST_0_PAYMENTACTION' => , //Sale, Order, or Authorization
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
250
            //'PAYMENTREQUEST_0_PAYMENTREQUESTID'
251
            //return urls
252
            'RETURNURL' => PayPalExpressCheckoutPayment_Handler::return_link(),
253
            'CANCELURL' => PayPalExpressCheckoutPayment_Handler::cancel_link(),
254
            //'PAYMENTREQUEST_0_NOTIFYURL' => //Instant payment notification
255
            //'CALLBACK'
256
            //'CALLBACKTIMEOUT'
257
            //shipping display
258
            //'REQCONFIRMSHIPPING' //require that paypal account address be confirmed
259
            'NOSHIPPING' => 1, //show shipping fields, or not 0 = show shipping, 1 = don't show shipping, 2 = use account address, if none passed
260
            //'ALLOWOVERRIDE' //display only the provided address, not the one stored in paypal
261
            //TODO: Probably overkill, but you can even include the prices,qty,weight,tax etc for individual sale items
262
            //other settings
263
            //'LOCALECODE' => //locale, or default to US
264
            'LANDINGPAGE' => 'Billing' //can be 'Billing' or 'Login'
265
        );
266
267
        if (!isset($extradata['Name'])) {
268
            $arr =  array();
269
            if (isset($extradata['FirstName'])) {
270
                $arr[] = $extradata['FirstName'];
271
            }
272
            if (isset($extradata['MiddleName'])) {
273
                $arr[] = $extradata['MiddleName'];
274
            }
275
            if (isset($extradata['Surname'])) {
276
                $arr[] = $extradata['Surname'];
277
            }
278
            $extradata['Name'] = implode(' ', $arr);
279
        }
280
        $extradata["OrderID"] = SiteConfig::current_site_config()->Title." ".$this->Order()->getTitle();
0 ignored issues
show
Documentation Bug introduced by
The method Order does not exist on object<PayPalExpressCheckoutPayment>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
281
        //add member & shipping fields, etc ...this will pre-populate the paypal login / create account form
282
        foreach (array(
283
            'Email' => 'EMAIL',
284
            'Name' => 'PAYMENTREQUEST_0_SHIPTONAME',
285
            'Address' => 'PAYMENTREQUEST_0_SHIPTOSTREET',
286
            'Address2' => 'PAYMENTREQUEST_0_SHIPTOSTREET2',
287
            'City' => 'PAYMENTREQUEST_0_SHIPTOCITY',
288
            'PostalCode' => 'PAYMENTREQUEST_0_SHIPTOZIP',
289
            'Region' => 'PAYMENTREQUEST_0_SHIPTOPHONENUM',
290
            'Phone' => 'PAYMENTREQUEST_0_SHIPTOPHONENUM',
291
            'Country' => 'PAYMENTREQUEST_0_SHIPTOCOUNTRYCODE',
292
            'OrderID' => 'PAYMENTREQUEST_0_DESC'
293
        ) as $field => $val) {
294
            if (isset($extradata[$field])) {
295
                $data[$val] = $extradata[$field];
296
            } elseif ($this->$field) {
297
                $data[$val] = $this->$field;
298
            }
299
        }
300
        //set design settings
301
        $data = array_merge($this->Config()->get("custom_settings"), $data);
302
        $response = $this->apiCall('SetExpressCheckout', $data);
303
        if (Config::inst()->get("PayPalExpressCheckoutPayment", "debug")) {
304
            $this->addDebugInfo("RESPONSE: ".print_r($response, 1));
305
            $debugmessage = "PayPal Debug:" .
306
                "\nMode: $mode".
0 ignored issues
show
The variable $mode seems only to be defined at a later point. Did you maybe move this code here without moving the variable definition?

This error can happen if you refactor code and forget to move the variable initialization.

Let’s take a look at a simple example:

function someFunction() {
    $x = 5;
    echo $x;
}

The above code is perfectly fine. Now imagine that we re-order the statements:

function someFunction() {
    echo $x;
    $x = 5;
}

In that case, $x would be read before it is initialized. This was a very basic example, however the principle is the same for the found issue.

Loading history...
307
                "\nAPI url: ".$this->getApiEndpoint().
308
                "\nRedirect url: ".$this->getPayPalURL($response['TOKEN']).
309
                "\nUsername: " .$this->Config()->get("API_UserName").
310
                "\nPassword: " .$this->Config()->get("API_Password").
311
                "\nSignature: ".$this->Config()->get("API_Signature").
312
                "\nRequest Data: ".print_r($data, true).
313
                "\nResponse: ".print_r($response, true);
314
            $this->addDebugInfo("DEBUG MESSAGE: ".$debugmessage);
315
        }
316
        if (!isset($response['ACK']) ||  !(strtoupper($response['ACK']) == "SUCCESS" || strtoupper($response['ACK']) == "SUCCESSWITHWARNING")) {
317
            $mode = ($this->Config()->get("test_mode") === true) ? "test" : "live";
0 ignored issues
show
$mode is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
318
            return null;
319
        }
320
        //get and save token for later
321
        $token = $response['TOKEN'];
322
        $this->Token = $token;
0 ignored issues
show
The property Token does not exist on object<PayPalExpressCheckoutPayment>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
323
        $this->write();
324
        return $this->getPayPalURL($token);
325
    }
326
327
    /**
328
     * see https://cms.paypal.com/us/cgi-bin/?cmd=_render-content&content_ID=developer/e_howto_api_nvp_r_DoExpressCheckoutPayment
329
     */
330
    public function confirmPayment()
0 ignored issues
show
confirmPayment uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
331
    {
332
        $data = array(
333
            'PAYERID' => $this->PayerID,
0 ignored issues
show
The property PayerID does not exist on object<PayPalExpressCheckoutPayment>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
334
            'TOKEN' => $this->Token,
0 ignored issues
show
The property Token does not exist on object<PayPalExpressCheckoutPayment>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
335
            'PAYMENTREQUEST_0_PAYMENTACTION' => "Sale",
336
            'PAYMENTREQUEST_0_AMT' => $this->Amount->Amount,
0 ignored issues
show
The property Amount does not exist on object<PayPalExpressCheckoutPayment>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
337
            'PAYMENTREQUEST_0_CURRENCYCODE' => $this->Amount->Currency,
0 ignored issues
show
The property Amount does not exist on object<PayPalExpressCheckoutPayment>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
338
            'IPADDRESS' => urlencode($_SERVER['SERVER_NAME'])
339
        );
340
        $response = $this->apiCall('DoExpressCheckoutPayment', $data);
341
        if (!isset($response['ACK']) ||  !(strtoupper($response['ACK']) == "SUCCESS" || strtoupper($response['ACK']) == "SUCCESSWITHWARNING")) {
342
            return null;
343
        }
344
        if (isset($response["PAYMENTINFO_0_TRANSACTIONID"])) {
345
            //' Unique transaction ID of the payment. Note:  If the PaymentAction of the request was Authorization or Order, this value is your AuthorizationID for use with the Authorization & Capture APIs.
346
            $this->TransactionID    = $response["PAYMENTINFO_0_TRANSACTIONID"];
0 ignored issues
show
The property TransactionID does not exist on object<PayPalExpressCheckoutPayment>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
347
        }
348
        //$transactionType 		= $response["PAYMENTINFO_0_TRANSACTIONTYPE"]; //' The type of transaction Possible values: l  cart l  express-checkout
0 ignored issues
show
Unused Code Comprehensibility introduced by
60% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
349
        //$paymentType			= $response["PAYMENTTYPE"];  	//' Indicates whether the payment is instant or delayed. Possible values: l  none l  echeck l  instant
0 ignored issues
show
Unused Code Comprehensibility introduced by
60% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
350
        //$orderTime 				= $response["ORDERTIME"];  		//' Time/date stamp of payment
0 ignored issues
show
Unused Code Comprehensibility introduced by
60% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
351
        //TODO: should these be updated like this?
352
        //$this->Amount->Amount	= $response["AMT"];  			//' The final amount charged, including any shipping and taxes from your Merchant Profile.
0 ignored issues
show
Unused Code Comprehensibility introduced by
58% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
353
        //$this->Amount->Currency= $response["CURRENCYCODE"];  	//' A three-character currency code for one of the currencies listed in PayPay-Supported Transactional Currencies. Default: USD.
0 ignored issues
show
Unused Code Comprehensibility introduced by
62% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
354
        //TODO: store this extra info locally?
355
        //$feeAmt					= $response["FEEAMT"];  		//' PayPal fee amount charged for the transaction
0 ignored issues
show
Unused Code Comprehensibility introduced by
60% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
356
        //$settleAmt				= $response["SETTLEAMT"];  		//' Amount deposited in your PayPal account after a currency conversion.
0 ignored issues
show
Unused Code Comprehensibility introduced by
60% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
357
        //$taxAmt					= $response["TAXAMT"];  		//' Tax charged on the transaction.
0 ignored issues
show
Unused Code Comprehensibility introduced by
60% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
358
        //$exchangeRate			= $response["EXCHANGERATE"];  	//' Exchange rate if a currency conversion occurred. Relevant only if your are billing in their non-primary currency. If the customer chooses to pay with a currency other than the non-primary currency, the conversion occurs in the customer's account.
0 ignored issues
show
Unused Code Comprehensibility introduced by
60% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
359
        if (isset($response["PAYMENTINFO_0_PAYMENTSTATUS"])) {
360
            switch (strtoupper($response["PAYMENTINFO_0_PAYMENTSTATUS"])) {
361
                case "PROCESSED":
362
                case "COMPLETED":
363
                    $this->Status = 'Success';
0 ignored issues
show
The property Status does not exist on object<PayPalExpressCheckoutPayment>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
364
                    $this->Message = _t('PayPalExpressCheckoutPayment.SUCCESS', "The payment has been completed, and the funds have been successfully transferred");
0 ignored issues
show
The property Message does not exist on object<PayPalExpressCheckoutPayment>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
365
                    break;
366
                case "EXPIRED":
367
                    $this->Message = _t('PayPalExpressCheckoutPayment.AUTHORISATION', "The authorization period for this payment has been reached");
0 ignored issues
show
The property Message does not exist on object<PayPalExpressCheckoutPayment>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
368
                    $this->Status = 'Failure';
0 ignored issues
show
The property Status does not exist on object<PayPalExpressCheckoutPayment>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
369
                    break;
370
                case "DENIED":
371
                    $this->Message = _t('PayPalExpressCheckoutPayment.FAILURE', "Payment was denied");
0 ignored issues
show
The property Message does not exist on object<PayPalExpressCheckoutPayment>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
372
                    $this->Status = 'Failure';
0 ignored issues
show
The property Status does not exist on object<PayPalExpressCheckoutPayment>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
373
                    break;
374
                case "REVERSED":
375
                    $this->Status = 'Failure';
0 ignored issues
show
The property Status does not exist on object<PayPalExpressCheckoutPayment>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
376
                    break;
377
                case "VOIDED":
378
                    $this->Message = _t('PayPalExpressCheckoutPayment.VOIDED', "An authorization for this transaction has been voided.");
0 ignored issues
show
The property Message does not exist on object<PayPalExpressCheckoutPayment>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
379
                    $this->Status = 'Failure';
0 ignored issues
show
The property Status does not exist on object<PayPalExpressCheckoutPayment>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
380
                    break;
381
                case "FAILED":
382
                    $this->Status = 'Failure';
0 ignored issues
show
The property Status does not exist on object<PayPalExpressCheckoutPayment>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
383
                    break;
384
                case "CANCEL-REVERSAL": // A reversal has been canceled; for example, when you win a dispute and the funds for the reversal have been returned to you.
385
                    break;
386
                case "IN-PROGRESS":
387
                    $this->Message = _t('PayPalExpressCheckoutPayment.INPROGRESS', "The transaction has not terminated");//, e.g. an authorization may be awaiting completion.";
0 ignored issues
show
The property Message does not exist on object<PayPalExpressCheckoutPayment>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
388
                    break;
389
                case "PARTIALLY-REFUNDED":
390
                    $this->Message = _t('PayPalExpressCheckoutPayment.PARTIALLYREFUNDED', "The payment has been partially refunded.");
0 ignored issues
show
The property Message does not exist on object<PayPalExpressCheckoutPayment>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
391
                    break;
392
                case "PENDING":
393
                    $this->Message = _t('PayPalExpressCheckoutPayment.PENDING', "The payment is pending.");
0 ignored issues
show
The property Message does not exist on object<PayPalExpressCheckoutPayment>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
394
                    if (isset($response["PAYMENTINFO_0_PENDINGREASON"])) {
395
                        $this->Message .= " ".$this->getPendingReason($response["PAYMENTINFO_0_PENDINGREASON"]);
0 ignored issues
show
The property Message does not exist on object<PayPalExpressCheckoutPayment>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
396
                    }
397
                    break;
398
                case "REFUNDED":
399
                    $this->Message = _t('PayPalExpressCheckoutPayment.REFUNDED', "Payment refunded.");
0 ignored issues
show
The property Message does not exist on object<PayPalExpressCheckoutPayment>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
400
                    break;
401
                default:
402
            }
403
        }
404
        //$reasonCode		= $response["REASONCODE"];
0 ignored issues
show
Unused Code Comprehensibility introduced by
67% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
405
        $this->write();
406
    }
407
408
    protected function getPendingReason($reason)
409
    {
410
        switch ($reason) {
411
            case "address":
412
                return _t('PayPalExpressCheckoutPayment.PENDING.ADDRESS', "A confirmed shipping address was not provided.");
413
            case "authorization":
414
                return _t('PayPalExpressCheckoutPayment.PENDING.AUTHORISATION', "Payment has been authorised, but not settled.");
415
            case "echeck":
416
                return _t('PayPalExpressCheckoutPayment.PENDING.ECHECK', "eCheck has not cleared.");
417
            case "intl":
418
                return _t('PayPalExpressCheckoutPayment.PENDING.INTERNATIONAL', "International: payment must be accepted or denied manually.");
419
            case "multicurrency":
420
                return _t('PayPalExpressCheckoutPayment.PENDING.MULTICURRENCY', "Multi-currency: payment must be accepted or denied manually.");
421
            case "order":
422
            case "paymentreview":
423
            case "unilateral":
424
            case "verify":
425
            case "other":
426
        }
427
    }
428
429
    /**
430
     * Handles actual communication with API server.
431
     */
432
    protected function apiCall($method, $data = array())
433
    {
434
        $this->addDebugInfo('---------------------------------------');
435
        $this->addDebugInfo('---------------------------------------');
436
        $this->addDebugInfo('---------------------------------------');
437
        $postfields = array(
438
            'METHOD' => $method,
439
            'VERSION' => $this->Config()->get("version"),
440
            'USER' => $this->Config()->get("API_UserName"),
441
            'PWD'=> $this->Config()->get("API_Password"),
442
            'SIGNATURE' => $this->Config()->get("API_Signature"),
443
            'BUTTONSOURCE' => $this->Config()->get("sBNCode")
444
        );
445
        if (Config::inst()->get("PayPalExpressCheckoutPayment", "debug")) {
446
            $this->addDebugInfo("STANDARD POSTING FIELDS ....  //// : ".print_r($postfields, 1));
447
            $this->addDebugInfo("ADDITIONAL POSTING FIELDS ....  //// : ".print_r($data, 1));
448
            $this->addDebugInfo("SENDING TO ....  //// : ".print_r($this->getApiEndpoint(), 1));
449
        }
450
        $postfields = array_merge($postfields, $data);
451
        //Make POST request to Paypal via RESTful service
452
        $rs = new RestfulService($this->getApiEndpoint(), 0); //REST connection that will expire immediately
453
        $rs->httpHeader('Accept: application/xml');
454
        $rs->httpHeader('Content-Type: application/x-www-form-urlencoded');
455
        $response = $rs->request('', 'POST', http_build_query($postfields));
456
        if (Config::inst()->get("PayPalExpressCheckoutPayment", "debug")) {
457
            $this->addDebugInfo('RESPONSE ....  //// : '.print_r($response, 1));
458
        }
459
        return $this->deformatNVP($response->getBody());
460
    }
461
462
    protected function deformatNVP($nvpstr)
463
    {
464
        $intial = 0;
465
        $nvpArray = array();
466
        while (strlen($nvpstr)) {
467
            //postion of Key
468
            $keypos= strpos($nvpstr, '=');
469
            //position of value
470
            $valuepos = strpos($nvpstr, '&') ? strpos($nvpstr, '&'): strlen($nvpstr);
471
            /*getting the Key and Value values and storing in a Associative Array*/
472
            $keyval=substr($nvpstr, $intial, $keypos);
473
            $valval=substr($nvpstr, $keypos+1, $valuepos-$keypos-1);
474
            //decoding the respose
475
            $nvpArray[urldecode($keyval)] =urldecode($valval);
476
            $nvpstr=substr($nvpstr, $valuepos+1, strlen($nvpstr));
477
        }
478
        return $nvpArray;
479
    }
480
481
    protected function getApiEndpoint()
0 ignored issues
show
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
482
    {
483
        return ($this->Config()->get("test_mode") === true) ? $this->Config()->get("test_API_Endpoint") : $this->Config()->get("API_Endpoint");
484
    }
485
486
    protected function getPayPalURL($token)
487
    {
488
        $url = ($this->Config()->get("test_mode") === true) ? $this->Config()->get("test_PAYPAL_URL") : $this->Config()->get("PAYPAL_URL");
489
        return $url.$token.'&useraction=commit'; //useraction=commit ensures the payment is confirmed on PayPal, and not on a merchant confirm page.
490
    }
491
492
493
    protected function addDebugInfo($msg)
494
    {
495
        $this->Debug .= "---------//------------\n\n".$msg;
0 ignored issues
show
The property Debug does not exist on object<PayPalExpressCheckoutPayment>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
496
        $this->write();
497
    }
498
}
499
500
/**
501
 * Handler for responses from the PayPal site
502
 */
503
class PayPalExpressCheckoutPayment_Handler extends Controller
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class should be in its own file to aid autoloaders.

Having each class in a dedicated file usually plays nice with PSR autoloaders and is therefore a well established practice. If you use other autoloaders, you might not want to follow this rule.

Loading history...
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
504
{
505
    private static $url_segment = 'paypalexpresscheckoutpayment_handler';
0 ignored issues
show
The property $url_segment is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
506
507
    protected $payment = null; //only need to get this once
508
509
    private static $allowed_actions = array(
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
The property $allowed_actions is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
510
        'confirm',
511
        'cancel'
512
    );
513
514
    public function Link($action = null)
515
    {
516
        return Controller::join_links(
517
            Director::baseURL(),
518
            $this->Config()->get("url_segment"),
519
            $action
520
        );
521
    }
522
523
    public function payment()
0 ignored issues
show
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
524
    {
525
        if ($this->payment) {
526
            return $this->payment;
527
        } elseif ($token = Controller::getRequest()->getVar('token')) {
528
            $payment =  PayPalExpressCheckoutPayment::get()
529
                ->filter(
530
                    array(
531
                        "Token" => $token,
532
                        "Status" => "Incomplete"
533
                    )
534
                )
535
                ->first();
536
            $this->payment = $payment;
537
            $this->payment->init();
538
            return $this->payment;
539
        }
540
        return null;
541
    }
542
543
    public function confirm($request)
0 ignored issues
show
The parameter $request is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
544
    {
545
        //TODO: pretend the user confirmed, and skip straight to results. (check that this is allowed)
546
        //TODO: get updated shipping details from paypal??
547
        if ($payment = $this->payment()) {
548
            if ($pid = Controller::getRequest()->getVar('PayerID')) {
549
                $payment->PayerID = $pid;
550
                $payment->write();
551
                $payment->confirmPayment();
552
            }
553
        } else {
0 ignored issues
show
This else statement is empty and can be removed.

This check looks for the else branches of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These else branches can be removed.

if (rand(1, 6) > 3) {
print "Check failed";
} else {
    //print "Check succeeded";
}

could be turned into

if (rand(1, 6) > 3) {
    print "Check failed";
}

This is much more concise to read.

Loading history...
554
            //something went wrong?	..perhaps trying to pay for a payment that has already been processed
555
        }
556
        $this->doRedirect();
557
        return;
558
    }
559
560
    public function cancel($request)
0 ignored issues
show
The parameter $request is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
561
    {
562
        if ($payment = $this->payment()) {
563
            //TODO: do API call to gather further information
564
            $payment->Status = "Failure";
565
            $payment->Message = _t('PayPalExpressCheckoutPayment.USERCANCELLED', "User cancelled");
566
            $payment->write();
567
        }
568
        $this->doRedirect();
569
        return;
570
    }
571
572
    protected function doRedirect()
573
    {
574
        $payment = $this->payment();
575
        if ($payment && $obj = $payment->PaidObject()) {
576
            $this->redirect($obj->Link());
577
            return;
578
        }
579
        $this->redirect(Director::absoluteURL('home', true)); //TODO: make this customisable in Payment_Controllers
580
        return;
581
    }
582
583
    public static function return_link()
584
    {
585
        return Director::absoluteURL(Config::inst()->get("PayPalExpressCheckoutPayment_Handler", "url_segment"), true)."/confirm/";
586
    }
587
588
    public static function cancel_link()
589
    {
590
        return Director::absoluteURL(Config::inst()->get("PayPalExpressCheckoutPayment_Handler", "url_segment"), true)."/cancel/";
591
    }
592
}
593