16

I have implemented a function that runs on each page that I want to restrict from non-logged in users. The function automatically redirects the visitor to the login page in the case of he or she is not logged in.

I would like to make a PHP function that is run from a exernal server and iterates through a number of set URLs (array with URLs that is for each protected site) to see if they are redirected or not. Thereby I could easily make sure if protection is up and running on every page.

How could this be done?

Thanks.

Annika Backstrom
  • 13,937
  • 6
  • 46
  • 52
Industrial
  • 41,400
  • 69
  • 194
  • 289
  • Redirected how? Called from what client? When logged in or when not logged in? What for? Would the script have to handle session cookies and other complicated things? – Pekka Jun 03 '10 at 10:02
  • Define "redirected URL" please. – Vladislav Rastrusny Jun 03 '10 at 10:02
  • See [How can I determine if a URL redirects in PHP?](http://stackoverflow.com/questions/427203/how-can-i-determine-if-a-url-redirects-in-php/481377#481377) – Matthew Flaschen Jun 03 '10 at 10:02
  • it is more like a scanner to find a vulnerability on the other server. – Your Common Sense Jun 03 '10 at 10:16
  • Updated again. Scanner is not a bad description actually. We will run a number of instances on the main server of the application and each application might be slightly different and modified according to each customer. Thereby it's very interesting to run a test to determine that password protection is up and running everywhere. – Industrial Jun 03 '10 at 10:19

12 Answers12

32
$urls = array(
    'http://www.apple.com/imac',
    'http://www.google.com/'
);

$ch = curl_init();

curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

foreach($urls as $url) {
    curl_setopt($ch, CURLOPT_URL, $url);
    $out = curl_exec($ch);

    // line endings is the wonkiest piece of this whole thing
    $out = str_replace("\r", "", $out);

    // only look at the headers
    $headers_end = strpos($out, "\n\n");
    if( $headers_end !== false ) { 
        $out = substr($out, 0, $headers_end);
    }   

    $headers = explode("\n", $out);
    foreach($headers as $header) {
        if( substr($header, 0, 10) == "Location: " ) { 
            $target = substr($header, 10);

            echo "[$url] redirects to [$target]<br>";
            continue 2;
        }   
    }   

    echo "[$url] does not redirect<br>";
}
Annika Backstrom
  • 13,937
  • 6
  • 46
  • 52
  • 3
    You can also use curl_getinfo($ch, CURLINFO_HTTP_CODE) to read the status code (301 or 302) – baloo Jun 03 '10 at 12:11
  • 4
    You can also save some bandwidth and processing power if you use `curl_setopt($handle, CURLOPT_NOBODY, true);`. This will only send a HTTP HEAD request. This way you won't have to cut off the body. See also this article: http://schlitt.info/opensource/blog/0606_sending_head_requests_with_extcurl.html – chiborg Apr 26 '12 at 21:25
  • I am new in php. It show me Fatal error: Call to undefined function curl_init() in C:\wamp\www\redirect-checker.php on line 3 – Sandeep Pattanaik Feb 26 '13 at 06:45
  • This error usually means you don't have cURL enabled in your server. Most likely, you'll need to find the php.ini file and find the line `;extension=php_curl.dll`. Remove the semi-colon from this line, or, if the line isn't present, add it without the leading semi-colon, and restart your WAMP server. I think it should work then. – PROGRAM_IX Aug 19 '13 at 10:07
  • 1
    @chiborg one thing to note is that many servers drop HEAD requests. – greatwitenorth Jan 09 '14 at 20:16
11

I use curl and only take headers, after I compare my url and url from header curl:

                $url="http://google.com";
                $ch = curl_init();

                curl_setopt($ch, CURLOPT_URL, $url);
                curl_setopt($ch, CURLOPT_TIMEOUT, '60'); // in seconds
                curl_setopt($ch, CURLOPT_HEADER, 1);
                curl_setopt($ch, CURLOPT_NOBODY, 1);
                curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
                curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
                $res = curl_exec($ch);

                if(curl_getinfo($ch)['url'] == $url){
                    echo "not redirect";
                }else {
                    echo "redirect";
                }
Piotr Kazuś
  • 346
  • 2
  • 12
4

You could always try adding:

curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); 

since 302 means it moved, allow the curl call to follow it and return whatever the moved url returns.

Bren1818
  • 2,612
  • 1
  • 23
  • 28
  • 1
    THIS...is actually the right answer. Thank you! It appears that without this curl stops at the content it first receives and doesn't follow the redirect if there is one. Thank you!!! – Let A Pro Do IT Aug 23 '14 at 04:21
2

Getting the headers with get_headers() and checking if Location is set is much simpler.

$urls = [
    "https://example-1.com",
    "https://example-2.com"
];

foreach ($urls as $key => $url) {

    $is_redirect = does_url_redirect($url) ? 'yes' : 'no';
    echo $url . ' is redirected: ' . $is_redirect . PHP_EOL;
}

function does_url_redirect($url){
    
    $headers = get_headers($url, 1);
    if (!empty($headers['Location'])) {
        return true;
    } else {
        return false;
    }
}
Aleksandar
  • 1,496
  • 1
  • 18
  • 35
1

I'm not sure whether this really makes sense as a security check.

If you are worried about files getting called directly without your "is the user logged in?" checks being run, you could do what many big PHP projects do: In the central include file (where the security check is being done) define a constant BOOTSTRAP_LOADED or whatever, and in every file, check for whether that constant is set.

Testing is great and security testing is even better, but I'm not sure what kind of flaw you are looking to uncover with this? To me, this idea feels like a waste of time that will not bring any real additional security.

Just make sure your script die() s after the header("Location:...") redirect. That is essential to stop additional content from being displayed after the header command (a missing die() wouldn't be caught by your idea by the way, as the redirect header would still be issued...)

If you really want to do this, you could also use a tool like wget and feed it a list of URLs. Have it fetch the results into a directory, and check (e.g. by looking at the file sizes that should be identical) whether every page contains the login dialog. Just to add another option...

Pekka
  • 442,112
  • 142
  • 972
  • 1,088
1

Do you want to check the HTTP code to see if it's a redirect?

    $params = array('http' => array(
        'method' => 'HEAD',
        'ignore_errors' => true
    ));

    $context = stream_context_create($params);
    foreach(array('http://google.com', 'http://stackoverflow.com') as $url) {
      $fp = fopen($url, 'rb', false, $context);
      $result = stream_get_contents($fp);

      if ($result === false) {
          throw new Exception("Could not read data from {$url}");
      } else if (! strstr($http_response_header[0], '301')) {
          // Do something here
      }
    }
baloo
  • 7,635
  • 4
  • 27
  • 35
1

I hope it will help you:

function checkRedirect($url)
{
        $headers = get_headers($url);
        if ($headers) {
            if (isset($headers[0])) {
                if ($headers[0] == 'HTTP/1.1 302 Found') {
                    //this is the URL where it's redirecting
                    return str_replace("Location: ", "", $headers[9]);
                }
            }
        }
        return false;
}
$isRedirect = checkRedirect($url);
if(!$isRedirect )
{
   echo "URL Not Redirected";
}else{
   echo "URL Redirected to: ".$isRedirect;
}
0

I modified Adam Backstrom answer and implemented chiborg suggestion. (Download only HEAD). It have one thing more: It will check if redirection is in a page of the same server or is out. Example: terra.com.br redirects to terra.com.br/portal. PHP will considerate it like redirect, and it is correct. But i only wanted to list that url that redirect to another URL. My English is not good, so, if someone found something really difficult to understand and can edit this, you're welcome.

function RedirectURL() {
    $urls = array('http://www.terra.com.br/','http://www.areiaebrita.com.br/');

    foreach ($urls as $url) {
        $ch = curl_init();

        curl_setopt($ch, CURLOPT_HEADER, true);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        // chiborg suggestion
        curl_setopt($ch, CURLOPT_NOBODY, true);

        // ================================
        //  READ URL
        // ================================

        curl_setopt($ch, CURLOPT_URL, $url);
        $out = curl_exec($ch);

        // line endings is the wonkiest piece of this whole thing
        $out = str_replace("\r", "", $out);
        echo $out;

        $headers = explode("\n", $out);

        foreach($headers as $header) {
            if(substr(strtolower($header), 0, 9) == "location:") {
                // read URL to check if redirect to somepage on the server or another one.
                // terra.com.br redirect to terra.com.br/portal. it is valid.
                // but areiaebrita.com.br redirect to bwnet.com.br, and this is invalid.
                // what we want is to check if the address continues being terra.com.br or changes. if changes, prints on page.

                // if contains http, we will check if changes url or not.
                // some servers, to redirect to a folder available on it, redirect only citting the folder. Example: net11.com.br redirect only to /heiden

                // only execute if have http on location
                if ( strpos(strtolower($header), "http") !== false) {
                    $address = explode("/", $header);

                    print_r($address);
                    // $address['0'] = http
                    // $address['1'] = 
                    // $address['2'] = www.terra.com.br
                    // $address['3'] = portal 

                    echo "url (address from array) = " . $url . "<br>";
                    echo "address[2] = " . $address['2'] . "<br><br>";

                    // url: terra.com.br
                    // address['2'] = www.terra.com.br

                    // check if string terra.com.br is still available in www.terra.com.br. It indicates that server did not redirect to some page away from here.
                    if(strpos(strtolower($address['2']), strtolower($url)) !== false) {
                        echo "URL NOT REDIRECT";
                    } else {
                        // not the same. (areiaebrita)
                        echo "SORRY, URL REDIRECT WAS FOUND: " . $url;  
                    }
                }
            }
        }
    }
}
eduardomozart
  • 1,444
  • 15
  • 14
0
function unshorten_url($url){
    $ch = curl_init();

    curl_setopt($ch, CURLOPT_HEADER, true);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_URL, $url);
    $out = curl_exec($ch);

    $real_url = $url;//default.. (if no redirect)

    if (preg_match("/location: (.*)/i", $out, $redirect))
        $real_url = $redirect[1];

    if (strstr($real_url, "bit.ly"))//the redirect is another shortened url
        $real_url = unshorten_url($real_url);

    return $real_url;
}
Ludo - Off the record
  • 5,153
  • 4
  • 31
  • 23
  • The php manual states that `strstr()` should not be used (use `strpos()` instead) when the goal is to check the existence of a string. – mickmackusa Mar 05 '21 at 20:27
0

You can use session,if the session array is not set ,the url redirected to a login page. .

luckydeng
  • 95
  • 1
  • 4
  • That's how my security is based basically, but won't make me able to see if a page from an array redirects or not. – Industrial Jun 03 '10 at 10:15
0

I have just made a function that checks if a URL exists or not

$ch = curl_init();
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

function url_exists($url, $ch) {
   curl_setopt($ch, CURLOPT_URL, $url);
   $out = curl_exec($ch);
   // line endings is the wonkiest piece of this whole thing
   $out = str_replace("\r", "", $out);

   // only look at the headers
   $headers_end = strpos($out, "\n\n");
   if( $headers_end !== false ) { 
       $out = substr($out, 0, $headers_end);
   }   
   //echo $out."====<br>";
   $headers = explode("\n", $out);
   //echo "<pre>";
   //print_r($headers);
   foreach($headers as $header) {
       //echo $header."---<br>";
       if( strpos($header, 'HTTP/1.1 200 OK') !== false ) { 
          return true;
          break;
       }
   }  

}

Now I have used an array of URLs to check if a URL exists as following:

$my_url_array = array('http://howtocode.pk/result', 'http://google.com/jobssss', 'https://howtocode.pk/javascript-tutorial/', 'https://www.google.com/');

for($j = 0; $j < count($my_url_array); $j++){

      if(url_exists($my_url_array[$j], $ch)){
           echo 'This URL "'.$my_url_array[$j].'" exists. <br>';
      }
}
Safeer Ahmed
  • 587
  • 6
  • 14
-2

I can't understand your question. You have an array with URLs and you want to know if user is from one of the listed URLs? If I'm right in understanding your quest:

$urls = array('http://url1.com','http://url2.ru','http://url3.org');
if(in_array($_SERVER['HTTP_REFERER'],$urls))
{
 echo 'FROM ARRAY';
} else {
 echo 'NOT FROM ARR';
}
Jon Lawton
  • 890
  • 3
  • 14
  • 33
GOsha
  • 689
  • 5
  • 13
  • Updated the question. I want to call every url in my array to see if they stay at the set url or redirects to the login page. – Industrial Jun 03 '10 at 10:14