Curl returning indefinite offset

Asked

Viewed 258 times

1

Based in this question, I was interested because some time ago I was making a follower generator pro Twitter (exchange of followers) and I got... but I thought it was cool the response of Inkeliz, and I’m trying, I’ve done everything not to ask for help but come on. We have the following code, which when giving a var_dump before the return return me HTTP 200 OK, OK so far so good, but 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 of the if was not working. What’s the problem?

FIRST EDITION:

took the if and changed the line:

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

To:

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

Worked :)

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

  • The error is on this line /name="csrf".*?value="(.*?)"/ swap for /value="(.*?)".*?name="csrf"/

  • It’s not, I wasn’t even going to test, but I’ll kk I’m sure it’s not there

  • give a var_dump in $matches before associating position 1 in $csrf and check if there really is a position 1

  • Returned to me array (size=0), but the problem is on the line that @Willbb quoted

  • changed the value of name="csrf" for authenticity_token and it worked

  • but I had to come but data...

Show 1 more comment

1 answer

2


Summary:

  1. The strlen($header) has nothing to do with getting the information, that’s a Curl requirement.

  2. The variable $cookie, how do you define the reference use (&$cookie) you will have all cookies.


There are N ways to save the cookie, basically exists:

  1. Storing in a traditional and official Curl way:

    Use the CURLOPT_COOKIEJAR as indicated in the documentation, it will save in a file containing all cookies in the format of the old browsers, I personally find this system to store files in 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 the CURLOPT_COOKIEFILE.

  2. Store in the database:

    Use the CURLOPT_HEADERFUNCTION or make an even bigger gambit using the subtr with the value of CURLINFO_HEADER_SIZE, but it won’t work if you use a proxy, because it can return a 100 Continue.

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


The magic of using the CURLOPT_HEADERFUNCTION, when you 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 at 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. The header data must be Written when using this callback Function. Return the number of bytes Written."

How do you use the use (&$cookie) PHP will write the information on $cookie, which was defined earlier, namely:

$variavel = '';

$funcao = function() use (&$variavel){
 $variavel = 'abc';
};

$funcao();

echo $variavel;
// Resultado: abc

The &$variavel is a "reference" and that already answers your question. But, there is still the 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 variable $cookie you will have all the cookies you have obtained.

In detail:

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

Checks if it is the header of Set-Cookie, after all there are several and 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, performed for the 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;

Upshot:

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

If there were more cookies would be listed as follows:

nome1=valor1; nome2=valor2; (...)
  • Very good your answer, but with me nothing works, the practical test I tested and did not work with me, will it be my apache... I want to pick up the twitter cookies...

  • Try to set to CURLOPT_SSL_VERIFYPEER and CURLOPT_SSL_VERIFYHOST for 0 to check, this is unsafe so in the example I did not use. I will edit.

  • It didn’t work, but I’m trying here.

  • When executing a var_dump(curl_error($curl)) results in what? Which is the Curl used, see running var_dump(curl_version()['version']);, if it is a very old version will cause problems. I have tested on three versions 7.50 and 7.51, on Windows and 7.54.0 on Centos.

  • var_dump(curl_error($curl)); returns an empty string, var_dump(curl_version()['version']); returns 7.50.1, but works with the site https://stackoverflow.com now https://twitter.com doesn’t work because it will be?

  • Twitter uses the set-cookies and not Set-Cookies, I will edit to support this in both answers. I don’t know if you have any RFC saying whether it should be uppercase or not, I’m curious now. I will edit soon.

  • Oshe unsuccessfully too... I’ll do a search. EDIT: twitter uses set-cookie without s in the end and all minuscule

  • Let’s go in the shawl so you can answer some questions of mine?

Show 4 more comments

Browser other questions tagged

You are not signed in. Login or sign up in order to post.