Thursday, March 31, 2011

Including pages with $_GET

I want url's like index.php?showuser=512, index.php?shownews=317 for pages i get content from db... and for regular pages index.php?page=about and so on WITHOUT mod-rewrite.

Invision Power Board has urls like this. I have looked through their code but I can't figure out how they do it.

I could do it like this:

if (ctype_digit($_GET['shownews'])) include('shownews.php'); 
elseif (ctype_digit($_GET['showuser'])) include('showuser.php');

// regular pages
elseif ($_GET['page'] == 'about') include('about.php');
elseif ($_GET['page'] == 'help') include('help.php'); 
elseif ($_GET['page'] == 'login') include('login.php');

But this feels too messy. Just curious how IPB does this. Is there a better way do to this? WITHOUT any mod-rewrite. Any one know? I doubt they do it like the above.

I can't do:

if (preg_match('/^[a-z0-9]+$/', $_GET['page'])) include('$_GET['page']');

Then I would get links like index.php?showuser&id=512 and that I dont like. (i know its not safe just showing the princip)

I like it this way, it's not the best but i like it so please be quiet about template engines, frameworks etc. Just be kind and answer my question... I just want to know how IPB does this.

Thanks Tomek

From stackoverflow
  • I don't know how IPB does this, let's get that out of the way. But, this is how I would approach this problem:

    First, I recognize that there are two kinds of GET parameters: page/identifier, and just page. These would get tested separately.

    Second, I recognize that all all get parameters match their filenames sans the php-suffix, so we can use this to our advantage.

    One of the most important things to remember is to never let GET-parameters affect our code unsanitized. In this case, we know which types of pages we can and want to show, so we can create a white-list out of these.

    So, onto the pseudo-y dispatcher code:

    $pagesWithId = array("shownews", "showuser", "showwhatever");
    $justPages   = array("about", "help", "login");
    
    foreach ($pagesWithId as $page) {
      if (isset($_GET[$page])) {
        $id = (int)$_GET[$page]; 
    
        include($page.'.php');
        die();
      }
    }
    
    if (in_array($_GET['page'], $justPages)) {
      include($_GET['page'].'.php');
      die();
    }
    
    // page not found
    show404OrHandleOtherwise();
    
  • For pages you just use a simple array.

    if (isset($pages[$_GET['page']])) include $pages[$_GET['page']];
    

    For shownews=317 You could make a simple conversion in your app. Depending on how you want to prioritize page or shownews etc:

    if (isset($pages[$_GET['page']])) {
      include $pages[$_GET['page']];
    } else {
      $possiblePages = array_filter(array_intersect_key($_GET, $pagesWithId), 'ctype_digit');
      if (!empty($possiblePages)) {
        $id = reset($possiblePages);
        $pageName = key($possiblePages);
        $page = $pagesWithId[$pageName];
        include $page;
      } else {
        //no valid pages
      }
    }
    

    Note: page "names" are array keys, and the value is the path, file and extension to include. More customizable.

0 comments:

Post a Comment