Page 1 of 4

Redirect user via 301 - too many loops?

Posted: Thu Oct 08, 2015 11:19 am
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);
          }
        }  
      }
      
      }
    }  

?>

Re: Redirect user via 301 - too many loops?

Posted: Thu Oct 08, 2015 7:49 pm
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?

Re: Redirect user via 301 - too many loops?

Posted: Fri Oct 09, 2015 3:20 am
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?

Re: Redirect user via 301 - too many loops?

Posted: Fri Oct 09, 2015 6:19 am
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.

Re: Redirect user via 301 - too many loops?

Posted: Fri Oct 09, 2015 7:15 am
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.

Re: Redirect user via 301 - too many loops?

Posted: Fri Oct 09, 2015 7:18 am
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.

Re: Redirect user via 301 - too many loops?

Posted: Fri Oct 09, 2015 9:12 am
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.

Re: Redirect user via 301 - too many loops?

Posted: Fri Oct 09, 2015 11:10 am
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.

Re: Redirect user via 301 - too many loops?

Posted: Fri Oct 09, 2015 11:17 am
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?

Re: Redirect user via 301 - too many loops?

Posted: Fri Oct 09, 2015 11:35 am
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
            }
        }
    }
}

Re: Redirect user via 301 - too many loops?

Posted: Tue Oct 13, 2015 8:39 am
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?!?!

Re: Redirect user via 301 - too many loops?

Posted: Tue Oct 13, 2015 8:43 am
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.

Re: Redirect user via 301 - too many loops?

Posted: Tue Oct 13, 2015 9:05 am
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.

Re: Redirect user via 301 - too many loops?

Posted: Tue Oct 13, 2015 9:14 am
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.

Re: Redirect user via 301 - too many loops?

Posted: Tue Oct 13, 2015 9:16 am
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.