• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

google / recaptcha / 23538245056

25 Mar 2026 11:16AM UTC coverage: 99.367% (-0.6%) from 100.0%
23538245056

Pull #611

github

web-flow
Merge f8a30086d into 0c1aee990
Pull Request #611: ⚡ Optimize stream reading using stream_get_contents

2 of 3 new or added lines in 1 file covered. (66.67%)

157 of 158 relevant lines covered (99.37%)

16.77 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

96.55
/src/ReCaptcha/RequestMethod/SocketPost.php
1
<?php
2

3
declare(strict_types=1);
4

5
/**
6
 * This is a PHP library that handles calling reCAPTCHA.
7
 *
8
 * BSD 3-Clause License
9
 *
10
 * @copyright (c) 2019, Google Inc.
11
 *
12
 * @see https://www.google.com/recaptcha
13
 * All rights reserved.
14
 *
15
 * Redistribution and use in source and binary forms, with or without
16
 * modification, are permitted provided that the following conditions are met:
17
 * 1. Redistributions of source code must retain the above copyright notice, this
18
 *    list of conditions and the following disclaimer.
19
 *
20
 * 2. Redistributions in binary form must reproduce the above copyright notice,
21
 *    this list of conditions and the following disclaimer in the documentation
22
 *    and/or other materials provided with the distribution.
23
 *
24
 * 3. Neither the name of the copyright holder nor the names of its
25
 *    contributors may be used to endorse or promote products derived from
26
 *    this software without specific prior written permission.
27
 *
28
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
29
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
31
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
32
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
34
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
35
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
36
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
37
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38
 */
39

40
namespace ReCaptcha\RequestMethod;
41

42
use ReCaptcha\ReCaptcha;
43
use ReCaptcha\RequestMethod;
44
use ReCaptcha\RequestParameters;
45

46
/**
47
 * Sends a POST request to the reCAPTCHA service, but makes use of fsockopen()
48
 * instead of get_file_contents(). This is to account for people who may be on
49
 * servers where allow_url_open is disabled.
50
 */
51
class SocketPost implements RequestMethod
52
{
53
    private string $siteVerifyUrl;
54

55
    /**
56
     * Only needed if you want to override the defaults.
57
     *
58
     * @param null|string $siteVerifyUrl URL for reCAPTCHA siteverify API
59
     */
60
    public function __construct(?string $siteVerifyUrl = null)
61
    {
62
        $this->siteVerifyUrl = (is_null($siteVerifyUrl)) ? ReCaptcha::SITE_VERIFY_URL : $siteVerifyUrl;
14✔
63
    }
64

65
    /**
66
     * Submit the POST request with the specified parameters.
67
     *
68
     * @param RequestParameters $params Request parameters
69
     *
70
     * @return string Body of the reCAPTCHA response
71
     */
72
    public function submit(RequestParameters $params): string
73
    {
74
        $errno = 0;
14✔
75
        $errstr = '';
14✔
76
        $urlParsed = parse_url($this->siteVerifyUrl);
14✔
77

78
        if (false === $urlParsed || !isset($urlParsed['host']) || !isset($urlParsed['path'])) {
14✔
79
            return '{"success": false, "error-codes": ["'.ReCaptcha::E_CONNECTION_FAILED.'"]}';
2✔
80
        }
81

82
        $handle = fsockopen('ssl://'.$urlParsed['host'], 443, $errno, $errstr, 30);
12✔
83

84
        if (false === $handle || 0 !== $errno || '' !== $errstr) {
12✔
85
            return '{"success": false, "error-codes": ["'.ReCaptcha::E_CONNECTION_FAILED.'"]}';
2✔
86
        }
87

88
        if (false === stream_set_timeout($handle, 60)) {
10✔
89
            return '{"success": false, "error-codes": ["'.ReCaptcha::E_CONNECTION_FAILED.'"]}';
2✔
90
        }
91

92
        $content = $params->toQueryString();
8✔
93

94
        $request = 'POST '.$urlParsed['path']." HTTP/1.0\r\n";
8✔
95
        $request .= 'Host: '.$urlParsed['host']."\r\n";
8✔
96
        $request .= "Content-Type: application/x-www-form-urlencoded\r\n";
8✔
97
        $request .= 'Content-length: '.strlen($content)."\r\n";
8✔
98
        $request .= "Connection: close\r\n\r\n";
8✔
99
        $request .= $content."\r\n\r\n";
8✔
100

101
        fwrite($handle, $request);
8✔
102
        $response = stream_get_contents($handle);
8✔
103

104
        fclose($handle);
8✔
105

106
        if (!is_string($response)) {
8✔
NEW
107
            $response = '';
×
108
        }
109

110
        if (0 !== strpos($response, 'HTTP/1.0 200 OK')) {
8✔
111
            return '{"success": false, "error-codes": ["'.ReCaptcha::E_BAD_RESPONSE.'"]}';
2✔
112
        }
113

114
        $parts = preg_split("#\n\\s*\n#Uis", $response);
6✔
115

116
        if (!is_array($parts) || !isset($parts[1])) {
6✔
117
            return '{"success": false, "error-codes": ["'.ReCaptcha::E_BAD_RESPONSE.'"]}';
2✔
118
        }
119

120
        return $parts[1];
4✔
121
    }
122
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc