cURL returning undefined offset

0

Based in this question , I was interested because some time ago I was doing a Twitter follower generator (followers exchange) and I managed ... but I found the answer to Inkeliz , and I'm trying, I tried hard not to ask for help but come on. We have the following code, which when giving a var_dump before return I get HTTP 200 OK , ok so far so good, but it is returning me:

  

Notice: Undefined offset: 1 in C: \ wamp64 \ www \ test \ index.php on line 37

<?php

$cookie = '';
$csrf = '';

$url = 'https://twitter.com';

$getCSRFToken = curl_init();

curl_setopt_array($getCSRFToken, [
        CURLOPT_URL             => $url,
        CURLOPT_CUSTOMREQUEST   => 'GET',
        CURLOPT_RETURNTRANSFER  => true,
        CURLOPT_SSL_VERIFYPEER  => false,
        CURLOPT_SSL_VERIFYHOST  => false,
        CURLOPT_USERAGENT       => $_SERVER['HTTP_USER_AGENT'],
        CURLOPT_REFERER         => $url,
        CURLOPT_HEADER          => true,
        CURLOPT_HEADERFUNCTION  => function($curl, $header) use (&$cookie){

            if(strpos($header, 'Set-Cookie:') === 0){
                if(preg_match('/Set-Cookie:\s?(.*?);/', $header, $matches)) {
                    $cookie .= $matches[1] . '; ';

                }
            }

            return strlen($header);
        }
    ]
);

$getCSRFToken = curl_exec($getCSRFToken);

preg_match('/name="csrf".*?value="(.*?)"/', $getCSRFToken, $matches);

$csrf = $matches[1];

if(preg_match('/name="csrf".*?value="(.*?)"/', $getCSRFToken, $matches)){
    $csrf = $matches[1];
}

I took if because if was not working. What is the problem?

FIRST EDITION:

I removed the if and changed the line:

preg_match('/name="csrf".*?value="(.*?)"/', $getCSRFToken, $matches);

To:

preg_match('/value="(.*?)" name="authenticity_token"/', $getCSRFToken, $matches);

It worked :)

Now comes another question, how do I use the value of return strlen($header); to save Cookies ?

    
asked by anonymous 01.07.2017 / 20:40

1 answer

2

Summary:

  • The strlen($header) has nothing to do with getting the information, this is a requirement of cURL.

  • The variable $cookie , as defined by the reference use (&$cookie) will have all cookies.

  • There are N ways to save cookie , basically there is:

  • Store traditionally and officially cURL:

    Use CURLOPT_COOKIEJAR as indicated in the documentation, it will save to a file containing all cookies in the format of old browsers, I personally find this system to store in files terrible, because every time you use cookies you will have to read a file on disk and it will save all cookies and not those that interest you.

    Then to set cookies use CURLOPT_COOKIEFILE .

  • Store in database:

    Use CURLOPT_HEADERFUNCTION or make an even bigger problem using subtr with CURLINFO_HEADER_SIZE value, but will not work if using a proxy, because it can return 100 Continue .

    Then to use it has two options CURLOPT_HTTPHEADER or CURLOPT_COOKIE , note is COOKIE and not COOKIEFILE .

  • The magic of using CURLOPT_HEADERFUNCTION , when you do this:

        CURLOPT_HEADERFUNCTION  => function($curl, $header) use (&$cookie){
    
            if(strpos($header, 'Set-Cookie:') === 0){
                if(preg_match('/Set-Cookie:\s?(.*?);/', $header, $matches)) {
                    $cookie .= $matches[1] . '; ';
    
                }
            }
    
            return strlen($header);
        }
    

    The function($curl, $header) use (&$cookie) will be executed for each header received, according to the documentation:

      

    "The name of a callback function where the callback function takes two parameters. The first is the cURL resource, the second is a string with the header data to be written. Return the number of bytes written. "

    As you use use (&$cookie) PHP will write the information in $cookie , which was previously defined, ie:

    $variavel = '';
    
    $funcao = function() use (&$variavel){
     $variavel = 'abc';
    };
    
    $funcao();
    
    echo $variavel;
    // Resultado: abc
    

    The &$variavel is a "reference" and this already answers your question. But, there is still return strlen($header); this is done for cURL to send the other information, because as documented:

      

    "Return the number of bytes written."

    So if you do:

        CURLOPT_HEADERFUNCTION  => function($curl, $header) use (&$cookie){
    
            if(strpos($header, 'Set-Cookie:') === 0){
                if(preg_match('/Set-Cookie:\s?(.*?);/', $header, $matches)) {
                    $cookie .= $matches[1] . '; ';
    
                }
            }
    
            return strlen($header);
        }
    

    The $cookie variable will have all cookies that have been obtained.

    In detail:

    if(strpos($header, 'Set-Cookie:') === 0){
    
      

    Checks if it is the header of Set-Cookie , after all there are several headers, starting with content-encoding and cache-control ...

    if(preg_match('/Set-Cookie:\s?(.*?);/', $header, $matches)) {
    
      

    You will get the value of the cookie and name, ignoring the domain, validity and any other information.

    Practical test, run for https://stackoverflow.com :

    /** 
        Este trecho de código possui falhas de segurança,
        não é recomendado utilizar isto, apenas para testes!
    **/
    
    $cookie = '';
    
    $curl = curl_init('https://stackoverflow.com');
    curl_setopt_array($curl, [
            CURLOPT_RETURNTRANSFER  => 1,
            CURLOPT_SSL_VERIFYPEER => 0,
            CURLOPT_SSL_VERIFYHOST => 0,
            CURLOPT_HEADERFUNCTION  => function($curl, $header) use (&$cookie){
                if(stripos($header, 'Set-Cookie:') === 0){
                    if(preg_match('/Set-Cookie:\s?(.*?);/i', $header, $matches)) {
                        $cookie .= $matches[1] . '; ';
                    }
                }
                return strlen($header);
            }
        ]
    );    
    curl_exec($curl);
    
    echo $cookie;
    

    Result:

    prov=afae05a0-3694-886d-fe23-fc34e5ae0b4e;
    

    If there were more cookies it would be listed as follows:

    nome1=valor1; nome2=valor2; (...)
    
        
    01.07.2017 / 22:54