Issues (49)

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/EwayPayment.php (46 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
2
3
/**
4
 * @see http://www.eway.com.au/developers/api/shared-payments
5
 * @see http://www.eway.com.au/docs/api-documentation/sharedpaymentpagedoc.pdf
6
 * http://www.eway.com.au/developers/resources/response-codes
7
 *
8
 *
9
 * test CC:
10
 * 4444333322221111
11
 * any expiry, name, etc...
12
 *
13
 */
14
class EwayPayment 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...
15
{
16
    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...
The property $db 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...
17
        'AuthorisationCode' => 'Text'
18
    );
19
20
    // Eway Information
21
22
    private static $privacy_link = 'https://www.eway.com.au/Company/About/Privacy.aspx';
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...
23
24
    private static $logo = '/payment_eway/images/eway.png';
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...
25
26
    // Company Information
27
28
    private static $page_title = 'Your Title';
0 ignored issues
show
The property $page_title 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
30
    private static $company_name = 'Your Company Name';
0 ignored issues
show
The property $company_name 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...
31
32
    private static $payment_explanation = 'Your payment will be processed by the eWay payment processing site.';
0 ignored issues
show
The property $payment_explanation 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
34
    /**
35
     * e.g. /themes/mytheme/images/myimage.png
36
     * make sure the location is SSL if you add it
37
     * @var String
38
     */
39
    private static $company_logo = 'Your company Logo file location';
0 ignored issues
show
The property $company_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...
40
41
    // URLs
42
43
    private static $url = 'https://au.ewaygateway.com/Request';
0 ignored issues
show
The property $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...
44
45
46
    private static $confirmation_url = 'https://au.ewaygateway.com/Result';
0 ignored issues
show
The property $confirmation_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...
47
48
    // Test Mode
49
50
    private static $test_customer_id = '87654321';
0 ignored issues
show
The property $test_customer_id 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...
51
52
    private static $test_customer_username = 'TestAccount';
0 ignored issues
show
The property $test_customer_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...
53
54
    /**
55
     * NB: this is a string... anything will divert to LIVE
56
     * unless it is set to "yes"
57
     * @var String
58
     */
59
    private static $test_mode = 'no';
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...
60
61
    // Account Information
62
63
    private static $customer_id;
0 ignored issues
show
The property $customer_id 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...
64
65
    private static $customer_username;
0 ignored issues
show
The property $customer_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...
66
67
    // Credit Cards
68
69
    private static $credit_cards = array(
0 ignored issues
show
The property $credit_cards 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...
70
        //'Visa' => 'payment/images/payments/methods/visa.jpg',
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...
71
        //'MasterCard' => 'payment/images/payments/methods/mastercard.jpg',
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...
72
        //'American Express' => 'payment/images/payments/methods/american-express.gif',
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...
73
        //'Dinners Club' => 'payment/images/payments/methods/dinners-club.jpg',
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...
74
        //'JCB' => 'payment/images/payments/methods/jcb.jpg'
75
    );
76
77
78
    protected $testCodes = array(
79
"0" => " --- SELECT RESPONSE TYPE ---",
80
"00" => "Transaction Approved approved",
81
"01" => "Refer to Issuer",
82
"02" => "Refer to Issuer, special",
83
"03" => "No Merchant",
84
"04" => "Pick Up Card",
85
"05" => "Do Not Honour",
86
"06" => "Error",
87
"07" => "Pick Up Card, Special",
88
"08" => "Honour With Identification approved",
89
"09" => "Request In Progress",
90
"10" => "Approved For Partial Amount approved",
91
"11" => "Approved, VIP approved",
92
"12" => "Invalid Transaction",
93
"13" => "Invalid Amount",
94
"14" => "Invalid Card Number",
95
"15" => "No Issuer",
96
"16" => "Approved, Update Track 3 approved",
97
"19" => "Re-enter Last Transaction",
98
"21" => "No Action Taken",
99
"22" => "Suspected Malfunction",
100
"23" => "Unacceptable Transaction Fee",
101
"25" => "Unable to Locate Record On File",
102
"30" => "Format Error",
103
"31" => "Bank Not Supported By Switch",
104
"33" => "Expired Card, Capture",
105
"34" => "Suspected Fraud, Retain Card",
106
"35" => "Card Acceptor, Contact Acquirer, Retain Card",
107
"36" => "Restricted Card, Retain Card",
108
"37" => "Contact Acquirer Security Department, Retain Card",
109
"38" => "PIN Tries Exceeded, Capture",
110
"39" => "No Credit Account",
111
"40" => "Function Not Supported",
112
"41" => "Lost Card",
113
"42" => "No Universal Account",
114
"43" => "Stolen Card",
115
"44" => "No Investment Account",
116
"51" => "Insufficient Funds",
117
"52" => "No Cheque Account",
118
"53" => "No Savings Account",
119
"54" => "Expired Card",
120
"55" => "Incorrect PIN",
121
"56" => "No Card Record",
122
"57" => "Function Not Permitted to Cardholder",
123
"58" => "Function Not Permitted to Terminal",
124
"59" => "Suspected Fraud",
125
"60" => "Acceptor Contact Acquirer",
126
"61" => "Exceeds Withdrawal Limit",
127
"62" => "Restricted Card",
128
"63" => "Security Violation",
129
"64" => "Original Amount Incorrect",
130
"66" => "Acceptor Contact Acquirer, Security",
131
"67" => "Capture Card",
132
"75" => "PIN Tries Exceeded",
133
"82" => "CVV Validation Error",
134
"90" => "Cutoff In Progress",
135
"91" => "Card Issuer Unavailable",
136
"92" => "Unable To Route Transaction",
137
"93" => "Cannot Complete, Violation Of The Law",
138
"94" => "Duplicate Transaction",
139
"96" => "System Error"
140
 );
141
142
    public function getPaymentFormFields()
143
    {
144
        $logo = '<img src="' . $this->config()->get('logo') . '" alt="Credit card payments powered by eWAY"/>';
145
        $privacyLink = '<a href="' . $this->config()->get('privacy_link') . '" target="_blank" title="Read eWAY\'s privacy policy">' . $logo . '</a>';
146
        $paymentsList = '';
147
        if ($cards = $this->config()->get('credit_cards')) {
148
            foreach ($cards as $name => $image) {
149
                $paymentsList .= '<img src="' . $image . '" alt="' . $name . '"/>';
150
            }
151
        }
152
        $paymentsList .= "<p>".$this->Config()->get("payment_explanation")."</p>";
153
        $fields = new FieldList(
154
            new LiteralField('EwayInfo', $privacyLink),
155
            new LiteralField('EwayPaymentsList', $paymentsList)
156
        );
157
        if (Director::isDev()) {
158
            $fields->push(new DropdownField("PaymentTypeTest", "Required outcome", $this->testCodes));
159
        }
160
        return $fields;
161
    }
162
163
    public function getPaymentFormRequirements()
164
    {
165
        return null;
166
    }
167
168
    public function processPayment($data, $form)
169
    {
170
171
        // 1) Get secured Eway url
172
173
        $url = $this->EwayURL();
174
        $response = file_get_contents($url);
175
        if ($response) {
176
            $response = Convert::xml2array($response);
177
            if (isset($response['Result']) && $response['Result'] == 'True' && isset($response['URI']) && $response['URI']) {
178
179
                // 2) Redirect to the secured Eway url
180
181
                $page = new Page();
182
183
                $page->Title = 'Redirection to eWAY...';
184
                $page->Logo = '<img src="' . $this->config()->get('logo') . '" alt="Payments powered by eWAY"/>';
185
                $page->Form = $this->EwayForm($response['URI']);
186
187
                $controller = new Page_Controller($page);
188
189
                $form = $controller->renderWith('PaymentProcessingPage');
190
191
                return EcommercePayment_Processing::create($form);
192
            }
193
        }
194
195
        $this->Status = 'Failure';
0 ignored issues
show
The property Status does not exist on object<EwayPayment>. 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...
196
        if ($response && isset($response['Error'])) {
197
            $this->Message = $response['Error'];
0 ignored issues
show
The property Message does not exist on object<EwayPayment>. 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...
198
        }
199
200
        $this->write();
201
202
        return $this->redirectToOrder();
203
    }
204
205
    public function EwayURL()
0 ignored issues
show
EwayURL uses the super-global variable $_REQUEST 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...
206
    {
207
208
        // 1) Main Informations
209
210
        $order = $this->Order();
0 ignored issues
show
Documentation Bug introduced by
The method Order does not exist on object<EwayPayment>? 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...
211
        //$items = $order->Items();
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...
212
        $member = $order->Member();
0 ignored issues
show
$member 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...
213
214
        // 2) Main Settings
215
216 View Code Duplication
        if ($this->config()->get('test_mode') == 'yes') {
0 ignored issues
show
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
217
            $inputs['CustomerID'] = $this->config()->get('test_customer_id');
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...
218
            $inputs['UserName'] = $this->config()->get('test_customer_username');
219
        } else {
220
            $inputs['CustomerID'] = $this->config()->get('customer_id');
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...
221
            $inputs['UserName'] = $this->config()->get('customer_username');
222
        }
223
        if ($this->config()->get('test_mode') == 'yes' && isset($_REQUEST["PaymentTypeTest"])) {
224
            $amount = round($this->Amount->getAmount())+(intval($_REQUEST["PaymentTypeTest"])/100);
0 ignored issues
show
The property Amount does not exist on object<EwayPayment>. 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...
225
        } else {
226
            $amount = $this->Amount->getAmount();
0 ignored issues
show
The property Amount does not exist on object<EwayPayment>. 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...
227
        }
228
        $inputs['Amount'] = number_format($amount, 2, '.', ''); //$decimals = 2, $decPoint = '.' , $thousands_sep = ''
0 ignored issues
show
Unused Code Comprehensibility introduced by
40% 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...
229
        $inputs['Currency'] = $this->Amount->getCurrency();
0 ignored issues
show
The property Amount does not exist on object<EwayPayment>. 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...
230
        $inputs['ReturnURL'] = $inputs['CancelURL'] = Director::absoluteBaseURL() . EwayPayment_Handler::complete_link($this);
231
232
        $inputs['CompanyName'] = $this->config()->get('company_name');
233
        $inputs['MerchantReference'] = $inputs['MerchantInvoice'] = $order->ID;
234
        //$inputs['InvoiceDescription'] =
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...
235
        $inputs['PageTitle'] = $this->config()->get('page_title');
236
        $inputs['PageDescription'] = 'Please fill the details below to complete your order.';
237
        if ($logo = $this->config()->get('company_logo')) {
238
            $inputs['CompanyLogo'] = Director::absoluteBaseURL() . $logo;
239
        }
240
241
        // 7) Prepopulating Customer Informations
242
243
        $address = $this->Order()->BillingAddress();
0 ignored issues
show
Documentation Bug introduced by
The method Order does not exist on object<EwayPayment>? 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...
244
245
        $inputs['CustomerFirstName'] = $address->FirstName;
246
        $inputs['CustomerLastName'] = $address->Surname;
247
        $inputs['CustomerAddress'] = "$address->Address $address->Address2";
248
        $inputs['CustomerPostCode'] = $address->PostalCode;
249
        $inputs['CustomerCity'] = $address->City;
250
        $inputs['CustomerCountry'] = (class_exists("Geoip") ? Geoip::countryCode2name($address->Country) : $address->Country);
251
        $inputs['CustomerPhone'] = $address->Phone;
252
        $inputs['CustomerEmail'] = $address->Email;
253
        $inputs['CustomerState'] = $address->RegionCode;
254
        if ($this->config()->get('test_mode') == 'yes') {
255
            $inputs['CompanyName'] = "TEST FOR ".$inputs['CompanyName'];
256
            debug::log(print_r($inputs, 1));
257
            debug::log($this->config()->get('url'));
258
        }
259
        return $this->config()->get('url') . '?' . http_build_query($inputs);
260
    }
261
262
    public function EwayForm($url)
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...
263
    {
264
        Requirements::javascript(THIRDPARTY_DIR . '/jquery/jquery.js');
265
        return <<<HTML
266
			<form id="EwayForm" method="post" action="$url">
267
				<input type="submit" value="Pay Now" />
268
				<p>Continue through to payment page - if this does not happen automatically then please click above.</p>
269
			</form>
270
			<script type="text/javascript">
271
				jQuery(document).ready(function() {
272
					window.setTimeout(
273
						function(){
274
							jQuery("input[type='submit']").hide();
275
							jQuery('#EwayForm').submit();
276
						},
277
						200
278
					);
279
				});
280
			</script>
281
HTML;
282
    }
283
284
    public function EwayConfirmationURL($code)
285
    {
286
        $inputs = array('AccessPaymentCode' => $code);
287 View Code Duplication
        if ($this->config()->get('test_mode') == 'yes') {
0 ignored issues
show
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
288
            $inputs['CustomerID'] = $this->config()->get('test_customer_id');
289
            $inputs['UserName'] = $this->config()->get('test_customer_username');
290
        } else {
291
            $inputs['CustomerID'] = $this->config()->get('customer_id');
292
            $inputs['UserName'] = $this->config()->get('customer_username');
293
        }
294
        return $this->config()->get('confirmation_url') . '?' . http_build_query($inputs);
295
    }
296
297
    public function populateDefaults()
298
    {
299
        parent::populateDefaults();
300
        $this->AuthorisationCode = md5(uniqid(rand(), true));
0 ignored issues
show
The property AuthorisationCode does not exist on object<EwayPayment>. 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...
301
    }
302
}
303
304
/**
305
 * Handler for responses from the Eway site
306
 */
307
class EwayPayment_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...
308
{
309
    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...
310
        "complete"
311
    );
312
313
    private static $url_segment = 'ewaypayment_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...
314
315
    public static function complete_link(EwayPayment $payment)
316
    {
317
        return Config::inst()->get('EwayPayment_Handler', 'url_segment') . "/complete?code={$payment->ID}-{$payment->AuthorisationCode}";
0 ignored issues
show
The property AuthorisationCode does not exist on object<EwayPayment>. 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...
318
    }
319
320
    /**
321
     * Manages the 'return' and 'cancel' replies
322
     */
323
    public function complete()
0 ignored issues
show
complete uses the super-global variable $_REQUEST 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...
324
    {
325
        $this->extend("EwayPayment_Handler_completion_start");
326
        if (isset($_REQUEST['code']) && $code = $_REQUEST['code']) {
327
            $params = explode('-', $code);
328
            if (count($params) == 2) {
329
                $payment = EwayPayment::get()->byID(intval($params[0]));
330
                if ($payment && $payment->AuthorisationCode == $params[1]) {
331
                    if (isset($_REQUEST['AccessPaymentCode'])) {
332
                        $url = $payment->EwayConfirmationURL($_REQUEST['AccessPaymentCode']);
333
                        $response = file_get_contents($url);
334
                        if ($response) {
335
                            $response = Convert::xml2array($response);
336
                            if (isset($response['ResponseCode']) && $response['ResponseCode'] == '00') {
337
                                $payment->Status = 'Success';
338
                            } else {
339
                                $payment->Status = 'Failure';
340
                            }
341
                        } else {
342
                            $payment->Status = 'Failure';
343
                        }
344
                        $payment->write();
345
                        $payment->redirectToOrder();
346
                    }
347
                }
348
            }
349
        }
350
    }
351
}
352