通过代理服务器进行SSL连接

I'm trying to connect to the Twitter api server to make an "Application-only Autentication". I don't care any other way to connect to Twitter. I need this specific method.

I need to go from localhost through my corporation's proxy to api.twitter.com which needs ssl

Following the instruction of this twitter developer's page https://dev.twitter.com/docs/auth/application-only-auth, i tried with:

cUrl:

try {
    $ch = curl_init();    
    curl_setopt($ch, CURLOPT_URL, $url);
    if ($this->proxy != '') {
        curl_setopt($ch, CURLOPT_PROXY, $this->proxy);
        curl_setopt($ch, CURLOPT_PROXYPORT, $this->port);
        curl_setopt($ch, CURLOPT_PROXYUSERPWD, $this->userpwd);
    }
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_SSLVERSION, 3);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
    curl_setopt($ch, CURLOPT_POST, 1);
    curl_setopt($ch, CURLOPT_HTTPHEADER, array("
         POST /oauth2/token HTTP/1.1
         Host: api.twitter.com
         User-Agent: My Twitter App v1.0.23
         Authorization: Basic ".base64_encode(urlencode($consumer_key).":".urlencode($consumer_secret))."
         Content-Type: application/x-www-form-urlencoded;charset=UTF-8
         Content-Length: 29
         Accept-Encoding: gzip
         grant_type=client_credentials
    "));
    $response = curl_exec($ch);
    if (FALSE === $response) throw new Exception(curl_error($ch), curl_errno($ch));
        curl_close($ch);
        var_dump(json_decode($response));
} 
catch(Exception $e) {
    trigger_error(sprintf('Curl failed with error #%d: %s', $e->getCode(), $e->getMessage()), E_USER_ERROR);
}

Which gives me

Fatal error: Curl failed with error #35: Unknown SSL protocol error in connection to api.twitter.com

file_get_contents:

$context = stream_context_create(array(
    "http" => array(
    "method"=>"CONNECT",
    "proxy" => $this->proxy.":".$this->port,
    "request_fulluri" => true,
    "header" => "
        POST /oauth2/token HTTP/1.1
        Host: api.twitter.com
        User-Agent: My Twitter App v1.0.23
        Proxy-Authorization: Basic ".base64_encode(urlencode($this->userpwd))."
        Authorization: Basic ".base64_encode(urlencode($consumer_key).":".urlencode($consumer_secret))."
        Content-Type: application/x-www-form-urlencoded;charset=UTF-8
        Content-Length: 29
        Accept-Encoding: gzip
        grant_type=client_credentials
        ",
    ),
));
$response = file_get_contents($url, False, $context);
var_dump(json_decode($response));

Which gives me

Warning: file_get_contents(https://api.twitter.com/oauth2/token) [function.file-get-contents]: failed to open stream: Cannot connect to HTTPS server through proxy

fsockopen:

$fp = fsockopen($this->proxy, $this->port);
fputs($fp, "
    POST /oauth2/token HTTP/1.1
    Host: api.twitter.com
    User-Agent: My Twitter App v1.0.23
    Authorization: Basic ".base64_encode(urlencode($consumer_key).":".urlencode($consumer_secret))."
    Content-Type: application/x-www-form-urlencoded;charset=UTF-8
    Content-Length: 29
    Accept-Encoding: gzip
    grant_type=client_credentials
");
$data="";
while (!feof($fp)) $data .= fgets($fp,1024);
fclose($fp);
var_dump($data);

Which gives me

HTTP/1.1 400 Bad Request
Cache-Control: no-cache
Pragma: no-cache
Content-Type: text/html; charset=utf-8
Proxy-Connection: close
Connection: close
Content-Length: 727

I am sure that the 443 port is open and it's not a problem of the localhost (I got the same error trying on an online server).

I tried even using CONNECT method instead of POST. I tried tunneling the proxy, but I'm neither sure I made it nor that that's the problem.

I'm running out ideas..

Found the problem. There's no need (maybe only in this case, i'm not sure) to base64 encode the credentials. They'll be encoded by the server.

I don't know the reason of that different error responses, but was in fact a problem of double encoding, because of which the server was not able to verify my credentials.

Try to remove this:

curl_setopt($ch, CURLOPT_SSLVERSION, 3);

You only have one value in this array, it's wrong.

curl_setopt($ch, CURLOPT_HTTPHEADER, array("
         POST /oauth2/token HTTP/1.1
         Host: api.twitter.com
         User-Agent: My Twitter App v1.0.23
         Authorization: Basic ".base64_encode(urlencode($consumer_key).":".urlencode($consumer_secret))."
         Content-Type: application/x-www-form-urlencoded;charset=UTF-8
         Content-Length: 29
         Accept-Encoding: gzip
         grant_type=client_credentials
    "));

Change the above for this:

$consumer_key = base64_encode(urlencode($consumer_key);
$consumer_secret = urlencode($consumer_secret);

curl_setopt($ch, CURLOPT_HTTPHEADER, array(
         "Host: api.twitter.com",
         "User-Agent: My Twitter App v1.0.23",
         "Authorization: Basic $consumer_key:$consumer_secret",
         "Content-Type: application/x-www-form-urlencoded;charset=UTF-8",
         "Accept-Encoding: gzip",
         "grant_type=client_credentials"
         ));

if you want to include the Content-Length: xx, you need to use strlen() to get string length of the post, ex;

$length = strlen($post_content);

Then add it to the CURLOPT_HTTPHEADER array:

"Content-Length: $length"