Redirect user via 301 - too many loops?

PHP programming forum. Ask questions or help people concerning PHP code. Don't understand a function? Need help implementing a class? Don't understand a class? Here is where to ask. Remember to do your homework!

Moderator: General Moderators

simonmlewis
DevNet Master
Posts: 4435
Joined: Wed Oct 08, 2008 3:39 pm
Location: United Kingdom
Contact:

Redirect user via 301 - too many loops?

Post by simonmlewis »

I am trying to write a dynamic script that will perform a 301 if a product ID either doesn't exist, or has been moved to a new Category or Sub Category.

The code below should first see if the product ID exists.
If it doesn't, then it will take the user to the SubID in the URL.
If that doesn't exist, it will go to the CatID.
If that doesn't exist either, it will finally go to a nice "page not found".

But if the Product ID DOES exist, but the CatID or SubID are incorrect (as in, they are not in the Product's row in the database... (product might have been moved to a new category), I want them to be 301d to the new URL.

Problem is, when I load a product page and alter the SubID to test it, it just loops and loops and never stops. Leaving a white page.

Code: Select all


function checkURL()
{
 $pageURL = (isset($_SERVER['HTTPS']) && ($_SERVER["HTTPS"] == "on")) ? 'https://' : 'http://';
 if ($_SERVER["SERVER_PORT"] != "80") {
  $pageURL .= $_SERVER["SERVER_NAME"].":".$_SERVER["SERVER_PORT"].$_SERVER["REQUEST_URI"];
} else {
  $pageURL .= $_SERVER["SERVER_NAME"].$_SERVER["REQUEST_URI"];
 }
 return $pageURL;
}
$url = checkURL();
$fullurl = "http://rs.site.co.uk"."$url";
$str = explode("/","$fullurl");


if (!isset($_SESSION["loggedin"])) 
{
  if (isset($id))
  {
    $urlfind = $str[count($str)-2];
    $urlsubname = $str[count($str)-3];
    $urlsubid = $str[count($str)-4];
    $urlcatname = $str[count($str)-5];
    $urlcatid = $str[count($str)-6];
    
    $query = "SELECT id FROM products WHERE id = :id";
    $result = $pdo->prepare($query);
    $result->execute(array(':id' => $id));
    $num_rows = $result->rowCount();
    // If the product ID is not found, it will revert to the Sub or Cat
    if ($num_rows == 0) 
    {
      $queryredir = ("SELECT DISTINCT subid FROM products WHERE subid =:urlsubid");
      $resultredir = $pdo->prepare($queryredir);
      $resultredir->execute(array(':urlsubid' => $urlsubid));
      $num_rowssub = $resultredir->rowCount();
      if ($num_rowssub == "1")
      {
        header("Location: /subcateg/".urlencode($urlcatid)."/".urlencode($urlcatname)."/".urlencode($urlsubid)."/".   urlencode($urlsubname)."/",TRUE,301);
      }
      if ($num_rowssub == "0")
      {
        $queryredir = ("SELECT DISTINCT catid FROM products WHERE catid =:urlcatid");
        $resultredir = $pdo->prepare($queryredir);
        $resultredir->execute(array(':urlcatid' => $urlcatid));
        $num_rowscat = $resultredir->rowCount();
        if ($num_rowscat == "1")
        {
          header("Location: /categ/".urlencode($urlcatid)."/".urlencode($urlcatname)."/",TRUE,301);
        }
        if ($num_rowscat == 0)
        {
        header("HTTP/1.1 404 Not Found", true, 404);
        include ("custom_404.php");
        exit();
        }
      }
      }
      // If the product ID *IS* found... is the rest of the URL correct?
      if ($num_rows <> 0)
      {
        $query2   = "SELECT COUNT(id) AS numrows FROM products WHERE (catid <> :c OR subid <>:s) AND id =:id";
        $result2  = $pdo->prepare($query2);
        $result2->execute(array(':c' => $_GET['c'],':s' => $_GET['s'],':id' => $id));
        $num_rows3 = $result2->rowCount();
        if ($num_rows3 == "1")
        {
          // gather the information for the new URL
          $query3 = ("SELECT catid, subid, catname, subname, id, title FROM products WHERE id =:id GROUP BY id");
          $result3 = $pdo->prepare($query3);
          $result3->execute(array(':id' => $id));
          while ($row = $result3->fetch(PDO::FETCH_OBJ)) 
          {
            $title = "$row->title"; 
            $findtitle ="/ /"; 
            $replacetitle ="-"; 
            $titlereplace = preg_replace ($findtitle, $replacetitle, $title); 
      
            $categ = "$row->catname"; 
            $findcateg ="/ /"; 
            $replacecateg ="-"; 
            $categreplace = preg_replace ($findcateg, $replacecateg, $categ);  
 
            $subcateg = "$row->subname"; 
            $findsubcateg ="/ /"; 
            $replacesubcateg ="-"; 
            $subcategreplace = preg_replace ($findsubcateg, $replacesubcateg, $subcateg); 
            // 301 to new product page URL
            header("Location: /product/".urlencode($row->catid)."/".urlencode($categreplace)."/".urlencode($row->subid)."/".urlencode($subcategreplace)."/".urlencode($row->id)."/".urlencode($titlereplace)."/",TRUE,301);
          }
        }  
      }
      
      }
    }  

?>
Love PHP. Love CSS. Love learning new tricks too.
All the best from the United Kingdom.
User avatar
Celauran
Moderator
Posts: 6427
Joined: Tue Nov 09, 2010 2:39 pm
Location: Montreal, Canada

Re: Redirect user via 301 - too many loops?

Post by Celauran »

Why are there so many queries? Why are you grouping by ID? Is ID not unique? Are catname and subcatname stored in the products table, or did you forget a JOIN?
simonmlewis
DevNet Master
Posts: 4435
Joined: Wed Oct 08, 2008 3:39 pm
Location: United Kingdom
Contact:

Re: Redirect user via 301 - too many loops?

Post by simonmlewis »

I think you are referring to Query 2 and Query 3.
Query 2 first checks if there is a product ID and if it is NOT using the CatID or the SubID.
Query 3 then looks for the correct information and rebuilds the URL. It has to do it as a Group, as I cannot do it with DISTINCT as I need more than one field.

Is that wrong?
Love PHP. Love CSS. Love learning new tricks too.
All the best from the United Kingdom.
User avatar
Celauran
Moderator
Posts: 6427
Joined: Tue Nov 09, 2010 2:39 pm
Location: Montreal, Canada

Re: Redirect user via 301 - too many loops?

Post by Celauran »

I don't know your database structure, so I can't say for certain, but it certainly looks wrong for a few reasons. You're querying the same table over and over again, adding more fields to the select each time. Your queries suggest that ID is not unique, which is definitely problematic.

Code: Select all

SELECT catid, subid, catname, subname, id, title FROM products WHERE id = :id
Why couldn't you start with that? If the product ID doesn't exist, you get no rows back and can still hit your first branching statement. If it does exist, you'd already have all the information you need to redirect them.
simonmlewis
DevNet Master
Posts: 4435
Joined: Wed Oct 08, 2008 3:39 pm
Location: United Kingdom
Contact:

Re: Redirect user via 301 - too many loops?

Post by simonmlewis »

Because on the first query, I need to find if it does not exist.
But on the next query, I need to find it if does exist, but NOT with those other credentials.
Love PHP. Love CSS. Love learning new tricks too.
All the best from the United Kingdom.
User avatar
Celauran
Moderator
Posts: 6427
Joined: Tue Nov 09, 2010 2:39 pm
Location: Montreal, Canada

Re: Redirect user via 301 - too many loops?

Post by Celauran »

If it doesn't exist, no rows will be returned. If it does, you get the correct values for cat, subcat, etc which you can then compare against the initial request.
simonmlewis
DevNet Master
Posts: 4435
Joined: Wed Oct 08, 2008 3:39 pm
Location: United Kingdom
Contact:

Re: Redirect user via 301 - too many loops?

Post by simonmlewis »

Ok so in MY version. it asks if that ID exists.
If it doesn't, then it queries the URLs Cat and Subs... so that far we know.

But what if it does exist, but not with that Catid or Subid... how do I do that within your suggestion... without doing it my way? Sorry I don't get it.

I'm saying if ($num_rows <>0)... then to see if there are any products with that ID but not those other bits. If there aren't, then it builds the query based on what IS available.
Love PHP. Love CSS. Love learning new tricks too.
All the best from the United Kingdom.
User avatar
Celauran
Moderator
Posts: 6427
Joined: Tue Nov 09, 2010 2:39 pm
Location: Montreal, Canada

Re: Redirect user via 301 - too many loops?

Post by Celauran »

The question still is whether IDs are unique. If they are, doing it my way you'd already have that information. You wouldn't need another query.
simonmlewis
DevNet Master
Posts: 4435
Joined: Wed Oct 08, 2008 3:39 pm
Location: United Kingdom
Contact:

Re: Redirect user via 301 - too many loops?

Post by simonmlewis »

The IDs are unique.
I don't see how your way works - sorry.
Can you give me a step by step pseudo-code of how yours works please?
Love PHP. Love CSS. Love learning new tricks too.
All the best from the United Kingdom.
User avatar
Celauran
Moderator
Posts: 6427
Joined: Tue Nov 09, 2010 2:39 pm
Location: Montreal, Canada

Re: Redirect user via 301 - too many loops?

Post by Celauran »

Something like this

Code: Select all

<?php

/**
 * $title = "$row->title";
 * $findtitle ="/ /";
 * $replacetitle ="-";
 * $titlereplace = preg_replace ($findtitle, $replacetitle, $title);
 * 
 * $categ = "$row->catname";
 * $findcateg ="/ /";
 * $replacecateg ="-";
 * $categreplace = preg_replace ($findcateg, $replacecateg, $categ);  
 * 
 * $subcateg = "$row->subname";
 * $findsubcateg ="/ /";
 * $replacesubcateg ="-";
 * $subcategreplace = preg_replace ($findsubcateg, $replacesubcateg, $subcateg);
 *
 * This is all the same thing. Let's make it a function
 */

function slugify($string, $find = ' ', $replace = '-')
{
    return str_replace($find, $replace, $string);
}

function checkURL()
{
    $pageURL = (isset($_SERVER['HTTPS']) && ($_SERVER["HTTPS"] == "on")) ? 'https://' : 'http://';
    if ($_SERVER["SERVER_PORT"] != "80") {
        $pageURL .= $_SERVER["SERVER_NAME"].":".$_SERVER["SERVER_PORT"].$_SERVER["REQUEST_URI"];
    } else {
        $pageURL .= $_SERVER["SERVER_NAME"].$_SERVER["REQUEST_URI"];
    }

    return $pageURL;
}

// Any reason for this? You could just use $_SERVER['REQUEST_URI'] directly
$url = checkURL();
$fullurl = "http://rs.site.co.uk"."$url";
$str = explode("/","$fullurl");

if (!isset($_SESSION["loggedin"]))
{
    if (isset($id))
    {
        $urlfind    = $str[count($str)-2];
        $urlsubname = $str[count($str)-3];
        $urlsubid   = $str[count($str)-4];
        $urlcatname = $str[count($str)-5];
        $urlcatid   = $str[count($str)-6];

        // Let's start by getting product information
        $query = "SELECT catid, subid, catname, subname, title FROM products WHERE id = :id";
        $stmt = $pdo->prepare($query);
        $stmt->execute(['id' => $id]);

        // If the product ID is not found, it will revert to the Sub or Cat
        if ($stmt->rowCount() == 0)
        {
            // This bit is fine
            // Snip for clarity
        }

        // If the product ID *IS* found... is the rest of the URL correct?
        // ID is unique. If rowCount isn't 0, then it's 1 and we've found the product
        else
        {
            // Just use the results of our first query
            $product    = $stmt->fetch(PDO::FETCH_OBJ);
            $title      = slugify($product->title);
            $catname    = slugify($product->catname);
            $subcatname = slugify($product->subname);

            if ($catname != $urlcatname) {
                // Category is wrong, fix it here
            } else if ($subname != $urlsubname) {
                // Subcategory is wrong, fix it here
            } else {
                // They're both right
            }
        }
    }
}
simonmlewis
DevNet Master
Posts: 4435
Joined: Wed Oct 08, 2008 3:39 pm
Location: United Kingdom
Contact:

Re: Redirect user via 301 - too many loops?

Post by simonmlewis »

How does that check for a product ID, that does NOT have the catid or subid in the URL?
In other words... the first one needs to check of the ID exists at all.... if it does not, then we points them to Cat or Sub.
But if it does, BUT... the subid and/or catid are wrong for that ID....

I don't think that's included in your code here?!?!
Love PHP. Love CSS. Love learning new tricks too.
All the best from the United Kingdom.
User avatar
Celauran
Moderator
Posts: 6427
Joined: Tue Nov 09, 2010 2:39 pm
Location: Montreal, Canada

Re: Redirect user via 301 - too many loops?

Post by Celauran »

Of course it's included. Product 303 belongs to category 12 and subcategory 22, as an example. The first query is going to return exactly that. You've got the category and subcategory values that were included in the request, and you've just pulled the correct values from the database. Compare those and correct/redirect as appropriate.

Code: Select all

SELECT catid, subid, catname, subname, title FROM products WHERE id = 303
This will return
catid = 12
subid = 22
catname = foo
subname = bar
title = Some product name

You don't really need anything else.

If they've requested yoursite.co.uk/12/foo/22/bar/303/some-product-name, everything matches and you carry on. If, however, they've requested yoursite.co.uk/12/apples/22/elephants/303/some-product-name you can easily see that catname and subname are wrong, grab the correct values from your query result above, and redirect them to the desired URL.
simonmlewis
DevNet Master
Posts: 4435
Joined: Wed Oct 08, 2008 3:39 pm
Location: United Kingdom
Contact:

Re: Redirect user via 301 - too many loops?

Post by simonmlewis »

Code: Select all

       else
        {
            // Just use the results of our first query
            $product    = $stmt->fetch(PDO::FETCH_OBJ);
            $title      = slugify($product->title);
            $catname    = slugify($product->catname);
            $subcatname = slugify($product->subname);

            if ($catname != $urlcatname) {
                // Category is wrong, fix it here
            } else if ($subname != $urlsubname) {
                // Subcategory is wrong, fix it here
            } else {
                // They're both right
            }
        }
Yep ok I see that now.
This page won't be interested if the product is found and they are correct..... but if one of those cat or subs are incorrect.

I guess the "// They're both right" could just be an exit.

I would need to rebuild the URL from the database. So I guess rather than doing an else for cat and and else for sub... I can do one for both:

Code: Select all

if ($catname != $urlcatname || $subname != $urlsubname) {

}
And I only see one way to capture the info - and that's to do a WHILE {}.
Maybe if I extract the true Cat, Sub, and the Catname and Subname at the top, I can use it further down there.
Love PHP. Love CSS. Love learning new tricks too.
All the best from the United Kingdom.
User avatar
Celauran
Moderator
Posts: 6427
Joined: Tue Nov 09, 2010 2:39 pm
Location: Montreal, Canada

Re: Redirect user via 301 - too many loops?

Post by Celauran »

simonmlewis wrote:And I only see one way to capture the info - and that's to do a WHILE {}.
How's that? With ID being unique, you know you're only getting one row back. The fetch call at the top gets you all of that info.
simonmlewis
DevNet Master
Posts: 4435
Joined: Wed Oct 08, 2008 3:39 pm
Location: United Kingdom
Contact:

Re: Redirect user via 301 - too many loops?

Post by simonmlewis »

Bugger - I missed the fetch call as I always just use a While....
Yes I see it. bu tneed to gather the Subid and catid too.
Love PHP. Love CSS. Love learning new tricks too.
All the best from the United Kingdom.
Post Reply