Passed
Push — 2.x ( a2237c...c5863b )
by Terry
02:56
created

ReCaptcha::form()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 22
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 18
nc 2
nop 0
dl 0
loc 22
rs 9.6666
c 0
b 0
f 0
1
<?php
2
/*
3
 * This file is part of the Shieldon package.
4
 *
5
 * (c) Terry L. <[email protected]>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
11
declare(strict_types=1);
12
13
namespace Shieldon\Firewall\Captcha;
14
15
use Shieldon\Firewall\Captcha\CaptchaProvider;
16
17
use function Shieldon\Firewall\get_request;
18
use function Shieldon\Firewall\unset_superglobal;
19
use function curl_error;
20
use function curl_exec;
21
use function curl_init;
22
use function curl_setopt;
23
use function json_decode;
24
25
/**
26
 * Google reCaptcha.
27
 */
28
class ReCaptcha extends CaptchaProvider
29
{
30
    protected $key = '';
31
    protected $secret = '';
32
    protected $version = 'v2';
33
    protected $lang = 'en';
34
35
    protected $googleServiceUrl = 'https://www.google.com/recaptcha/api/siteverify';
36
37
    /**
38
     * Constructor.
39
     *
40
     * It will implement default configuration settings here.
41
     *
42
     * @array $config
43
     *
44
     * @return void
45
     */
46
    public function __construct(array $config = [])
47
    {
48
        parent::__construct();
49
        
50
        foreach ($config as $k => $v) {
51
            if (isset($this->{$k})) {
52
                $this->{$k} = $v;
53
            }
54
        }
55
    }
56
57
    /**
58
     * Response the result from Google service server.
59
     *
60
     * @return bool
61
     */
62
    public function response(): bool
63
    {
64
        $postParams = get_request()->getParsedBody();
65
66
        if (empty($postParams['g-recaptcha-response'])) {
67
            return false;
68
        }
69
70
        $flag = false;
71
        $reCaptchaToken = str_replace(["'", '"'], '', $postParams['g-recaptcha-response']);
72
73
        $postData = [
74
            'secret' => $this->secret,
75
            'response' => $reCaptchaToken,
76
        ];
77
78
        $ch = curl_init();
79
        curl_setopt($ch, CURLOPT_URL, $this->googleServiceUrl);
0 ignored issues
show
Bug introduced by
It seems like $ch can also be of type false; however, parameter $ch of curl_setopt() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

79
        curl_setopt(/** @scrutinizer ignore-type */ $ch, CURLOPT_URL, $this->googleServiceUrl);
Loading history...
80
        curl_setopt($ch, CURLOPT_HTTPHEADER, array('Expect:'));
81
        curl_setopt($ch, CURLOPT_POST, 2);
82
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
83
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
84
        curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);
85
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
86
87
        $ret = curl_exec($ch);
0 ignored issues
show
Bug introduced by
It seems like $ch can also be of type false; however, parameter $ch of curl_exec() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

87
        $ret = curl_exec(/** @scrutinizer ignore-type */ $ch);
Loading history...
88
89
        // @codeCoverageIgnoreStart
90
        if (curl_errno($ch)) {
0 ignored issues
show
Bug introduced by
It seems like $ch can also be of type false; however, parameter $ch of curl_errno() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

90
        if (curl_errno(/** @scrutinizer ignore-type */ $ch)) {
Loading history...
91
            echo 'error:' . curl_error($ch);
0 ignored issues
show
Bug introduced by
It seems like $ch can also be of type false; however, parameter $ch of curl_error() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

91
            echo 'error:' . curl_error(/** @scrutinizer ignore-type */ $ch);
Loading history...
92
        }
93
        // @codeCoverageIgnoreEnd
94
95
        if (isset($ret) && $ret != false) {
0 ignored issues
show
Bug introduced by
It seems like you are loosely comparing $ret of type boolean|string against false; this is ambiguous if the string can be empty. Consider using a strict comparison !== instead.
Loading history...
96
            $tmp = json_decode($ret);
0 ignored issues
show
Bug introduced by
It seems like $ret can also be of type true; however, parameter $json of json_decode() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

96
            $tmp = json_decode(/** @scrutinizer ignore-type */ $ret);
Loading history...
97
            if ($tmp->success == true) {
98
                $flag = true;
99
            }
100
        }
101
102
        curl_close($ch);
0 ignored issues
show
Bug introduced by
It seems like $ch can also be of type false; however, parameter $ch of curl_close() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

102
        curl_close(/** @scrutinizer ignore-type */ $ch);
Loading history...
103
104
        // Prevent detecting POST method on RESTful frameworks.
105
        unset_superglobal('g-recaptcha-response', 'post');
106
107
        return $flag;
108
    }
109
110
    /**
111
     * Output a required HTML for reCaptcha v2.
112
     *
113
     * @return string
114
     */
115
    public function form(): string
116
    {
117
        $html = '<div>';
118
        $html .= '<div style="display: inline-block">';
119
        if ('v3' !== $this->version) {
120
            $html .= '<script src="https://www.google.com/recaptcha/api.js?hl=' . $this->lang . '"></script>';
121
            $html .= '<div class="g-recaptcha" data-sitekey="' . $this->key . '"></div>';
122
        } else {
123
            $html .= '<input type="hidden" name="g-recaptcha-response" id="g-recaptcha-response" value="">';
124
            $html .= '<script src="https://www.google.com/recaptcha/api.js?render=' . $this->key . '&hl=' . $this->lang . '"></script>';
125
            $html .= '<script>';
126
            $html .= '    grecaptcha.ready(function() {';
127
            $html .= '        grecaptcha.execute("' . $this->key . '", {action: "homepage"}).then(function(token) {';
128
            $html .= '            document.getElementById("g-recaptcha-response").value = token;';
129
            $html .= '        }); ';
130
            $html .= '    });';
131
            $html .= '</script>';
132
        }
133
        $html .= '</div>';
134
        $html .= '</div>';
135
136
        return $html;
137
    }
138
}
139