1. Advertising
    y u no do it?

    Advertising (learn more)

    Advertise virtually anything here, with CPM banner ads, CPM email ads and CPC contextual links. You can target relevant areas of the site and show ads based on geographical location of the user if you wish.

    Starts at just $1 per CPM or $0.10 per CPC.

Poor Man CMS

Discussion in 'PHP' started by Puntocom81, Aug 3, 2016.

  1. #1
    Hello. I'm trying to put together some pieces of code to make a basic Poor man CMS. I'm looking for these features:
    • Pagination.
    • Full Friendly URLs.
    • Articles.
    • Tags.
    • Flat files instead of database driven.
    Some doubts

    There is a problem in the pagination list:
    • Element 1 has url /articles/0 instead of /articles.
    • Element 2 has url /articles/1 instead of /articles/2.
    What would be the best approach to add a tag system? the articles have an ID. I have thought about creating a file named tags.txt assigning tags to each article ID in this way:

    
    1 tag1,tag2,tag3
    2 tag2
    3 tag4,tag5
    
    Code (markup):
    And then processing it with PHP. Is it a good idea?

    My programming knowledge is very limited - only a bit of basic C. Any help is appreciated.

    Actual code

    Most of it is taken from @deathshadow 's contribution to several forums and his website Cutcodedown. Pagination is taken from the modification done to @Jeremy Benson 's code. I made some modifications.

    index.php
    
    <?php
    // start compression first since it does a heading and starts buffering
    define('CONTENT_ENCODING',
       (strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'x-gzip') !== false) ? 'x-gzip' :
       (strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') !== false) ? 'gzip' :
       false
    );
    if (CONTENT_ENCODING) include('libs/gzip.lib.php');
    
    function cleanPath($path) {
       return trim(str_replace(['\\','%5C'],'/',$path),'/');
    }
    
    function bomb($title, $message) {
       template_header('ERROR - ' . $title);
       echo '
         <div id="fatalError">
           <h2>
             ',$title,'
           </h2>
           <p>',$message,'</p>
           <p><strong>EXECUTION HALTED</strong></p>
         <!-- #fatalError --></div>';
       template_footer();
       die;
    }
    
    final class request {
       private static $data = [];
       public static function value($index = 0, $clean = false) {
         if ($index === true) { $index = 0; $clean = true; }
         if (count(self::$data) == 0) {
           $path = cleanPath(parse_url($_SERVER['REQUEST_URI'],PHP_URL_PATH));
           if (strpos($path,'..')) bomb('hackingDetected', 'uptreeFail');
           $path = substr($path, strlen(HTTP_ROOT) - 1);
           self::$data = empty($path) ? ['default'] : explode('/',$path);
           foreach (self::$data as &$p) $p = urldecode($p);
         }
         return isset(self::$data[$index]) ? (
           $clean ? cleanName(self::$data[$index]) : self::$data[$index]
         ) : false;
       }
    } // class request. request::value(0) return first parameter.
    
    
    /*
    define('SCRIPT_PATH', cleanPath(pathinfo($_SERVER['SCRIPT_NAME'], PATHINFO_DIRNAME)));
    define('ROOT_HTTP', '/' . SCRIPT_PATH . (SCRIPT_PATH == '' ? '' : '/'));
    define('ROOT_LOCAL', pathinfo($_SERVER['SCRIPT_FILENAME'], PATHINFO_DIRNAME) . '/');
    define('HOST_PROTOCOL', 'http' . (
       isset($_SERVER['HTTPS']) && ($_SERVER['HTTPS'] != 'off') ? 's' : ''
    ) . '://');
    define('HOST_HTTP', HOST_PROTOCOL . $_SERVER['HTTP_HOST']);
    define('BASE_HTTP', HOST_HTTP . ROOT_HTTP);
    define('PATH_HTTP',
       '/' . parse_url(cleanPath($_SERVER['REQUEST_URI']), PHP_URL_PATH)
    );
    define('FULL_HTTP', HOST_HTTP . PATH_HTTP);
    define('CANONICAL_PATH', request::getPath());
    define('CANONICAL_URI', HOST_PROTOCOL . WORKING_DOMAIN . '/' . CANONICAL_PATH);
    define('CANONICAL_URIe', urlencode(CANONICAL_URI));
    */
    
    define('SCRIPT_PATH', cleanPath(pathinfo($_SERVER['SCRIPT_NAME'], PATHINFO_DIRNAME)));
    define('ROOT_HTTP', '/' . SCRIPT_PATH . (SCRIPT_PATH == '' ? '' : '/'));
    define('SCRIPT_FILENAME',cleanPath($_SERVER['SCRIPT_FILENAME']));
    define('HTTP_ROOT',str_ireplace('index.php','',$_SERVER['PHP_SELF']));
    define('LOCAL_ROOT',str_ireplace('index.php','',SCRIPT_FILENAME));
    define('HTTP_THEME', HTTP_ROOT . 'theme/');
    require_once('setup.php');
    
    switch(request::value()) {
      case 'article':
      require_once('theme/article.template.php');
      break;
      default: // then it must be the index, a static or Not Found
      require_once(
      is_file($targetFile = 'statics/' . request::value() . '.php') ?
      $targetFile :
      'statics/404.php'
    );
    
    }
    
    ?>
    
    Code (markup):
    libs/articles.lib.php
    
    <?php
    
    function newsNumber() {
    global $article_dir,$users,$txt_convert;
    
       $articles=scandir($article_dir,1);
      return   (count($articles)-2); // Number of files except . and ..
    }
    
    function news($mode,$start,$count) {
    global $article_dir,$users,$txt_convert;
    
       $articles=scandir($article_dir,1);
       $t=$start;
       $end=$t+$count;
       if ($end>count($articles)) { $end=count($articles); }
       while ($t<$end) {
         switch ($articles[$t])   {
     
      case '.':
           case '..':
           break;
     
           default:
             list($id, $date,$subject,$author)=explode('_',$articles[$t]);
             //$author=$users[str_replace('.article.txt','',$author)];
      $author = str_replace('.article.txt','',$author);
             $date=date("d F Y",
               mktime(0,0,0,
                 substr($date,4,2),
                 substr($date,6,2),
                 substr($date,0,4)
               )
             );
             $contents=str_ireplace($txt_convert['in'],$txt_convert['out'],
               trim(file_get_contents($article_dir.'/'.$articles[$t]))
             );
             echo '
               <div class="article">
               <h3>
             ';
             echo '
                       ',$subject,' <span>',$date,'</span>';
    
             echo '
                     </h3>
             ';
             echo '<div class="article_body">';
             echo '
                       <p>',$contents,'</p>
                       <div class="author">Author: ',$author,'</div>
                       <div class="id">ID: ',$id,'</div>
             ';
             echo '</div>';
             echo '
                   </div>
             ';
           break;
         }
         $t++;
       }
    }
    
    ?>
    
    Code (markup):
    libs/paginate.lib.php
    
    <?php
    
    class Paginate {
    
       private
         $perPage,
         $maxShow,
         $middle,
         $href,
         $current,
         $lastPage;
    
       public function __construct(
         $href = '/',
         $current = 0,
         $total = 0,
         $perPage = 5,
         $maxShow = 5 //,
         //$field = 'page'
       ) {
    
         //$this->href = ' href="' . $href . (
         //   strpos($href, '?') === FALSE ? '?' : '&amp;'
         //) . $field . '=';
      $this->href = ' href="';
         $this->current = $current;
         $this->total = $total;
         $this->perPage = $perPage;
         $this->maxShow = $maxShow;
         $this->middle = floor($maxShow / 2);
         $this->lastPage = floor(($total - 1) / $perPage);
    
    
       } // Paginate::__construct
     
       public function getLimits() {
         return [
           ':offset' => $this->current * $this->perPage,
           ':limit' => $this->perPage
         ];
       }
     
       private function anchorLine($page, $text, $title = false, $rel = false) {
         $tag = $page < 0 ? 'span' : 'a';
         echo '
             <li><', $tag, (
               $page >= 0 ? $this->href . $page . '"' : ''
             ), (
               $page == -2 ? ' class="disabled"' : ''
             ), (
               $title ? ' title="' . $title . '"' : ''
             ), (
               $rel ? ' rel="' . $rel . '"' : ''
             ), '>', $text, '</', $tag, '></li>';
       }
    
       public function show() {
    
         if ($this->total <= $this->perPage) return;
       
         echo '
           <ul class="pagination">';
    
         if (($this->lastPage > 0) && ($this->current > 0)) {
           $this->anchorLine(0, 'First');
           $this->anchorLine($this->current - 1, '&#x25C0;', 'Previous Page', 'prev');
         } else {
           $this->anchorLine(-2, 'First');
           $this->anchorLine(-2, '&#x25C0;');
         }
    
         if ($this->lastPage >= $this->maxShow) {
           $counter = ($this->current <= $this->middle) ? 0 : $this->current - $this->middle;
           $endPage = $counter + $this->maxShow;
           if ($endPage > $this->lastPage) {
             $counter = $this->lastPage - $this->maxShow;
             if ($counter < 0) $counter = 0;
             $endPage = $this->lastPage;
           }
         } else {
           $counter = 0;
           $endPage = $this->lastPage;
         }
    
         while ($counter <= $endPage) $this->anchorLine(
           $counter == $this->current ? -1 : $counter,
           ++$counter
         );
    
         if (($this->lastPage > 0) && ($this->current < $this->lastPage)) {
           $this->anchorLine($this->current + 1, '&#x25B6;', 'Next Page', 'next');
           $this->anchorLine($this->lastPage, 'Last');
         } else {
           $this->anchorLine(-2, '&#x25B6;');
           $this->anchorLine(-2, 'Last');
         }
    
         echo '
           </ul>';
    
       } // Paginate::show
    
    } // Paginate
    
    Code (markup):
    libs/gzip.lib.php
    
    <?php
    /*
       gzip.lib.php
      
       Version 1.0 Jason M. Knight, August 2009
      
       Uses a proper exit handler to provide automation of gzip compression of our
       PHP output with little if any headaches.
      
       ASSUMES:
         CONTENT_ENCODING contains either 'x-gzip' or 'gzip' based on the value in
         HTTP_ACCEPT_ENCODING. See "defines.php" to see how this is set.
        
       If STRIP_WHITESPACE is defined whitespace between tags or at the start of
       lines will be stripped, as will comments. Whitespace between a tag and
       CDATA or between attributes will be left alone.
      
    */
    
    ob_start();
    ob_implicit_flush(0);
    register_shutdown_function(function() {
       header('Content-Encoding: ' . CONTENT_ENCODING);
       $contents = ob_get_contents();
       if (defined('STRIP_WHITESPACE')) $contents = preg_replace(
         ['#<!--.*?-->#s', '#>\s+<#', '#\n\s+<#'],
         ['', '><', '<'],
         $data
       );
      ob_end_clean();
       echo "\x1f\x8b\x08\x00\x00\x00\x00\x00",
         substr(gzcompress($contents, 6), 0, -4);
    });
    [/B]
    
    Code (markup):
    statics/articles.php
    
    <?php require_once('theme/index.template.php'); template_header(
       false, // don't show "pageTitle - Site title"
       'seven,or,eight,words,that,exist,in,body', // keywords
       'A short natural language description describing the site'
    ); require_once('libs/articles.lib.php');
      require_once('libs/paginate.lib.php');
    
    if (request::value(2)!='') {
      echo '<h1>Error 404</h1>';
      http_response_code(404);
      template_footer();
      die();
    }
    echo '
    
    <h2>Articles</h2>
    <p>
       This is where your page unique content would go!
    </p>
    
    ';
    
    //$page = isset($_GET['page']) && is_numeric($_GET['page']) ? $_GET['page'] : 0;
    $page = request::value(1);
    
    $paginator = new Paginate('', $page, newsNumber());
    $paginator->show();
    
    $limits = $paginator->getLimits();
    
    news(false, $limits[':offset'], $limits[':limit']);
    
    template_footer(); ?>
    
    Code (markup):
    theme/index.template.php
    
    <?php
    
    function template_header(
       $pageTitle = false,
       $keywords = false,
       $description = false
    ) {
    
       echo '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
    <html
       xmlns="http://www.w3.org/1999/xhtml"
       lang="en"
       xml:lang="en"
    ><head>
    
    <meta
       http-equiv="Content-Type"
       content="text/html; charset=utf-8"
    />
    
    <meta
       http-equiv="Content-Language"
       content="en"
    />
    
    <meta
       name="viewport"
       content="width=device-width; initial-scale=1.0"
    />';
    
       if ($keywords) echo '
     
    <meta
       name="keywords"
       content="', $keywords, '"
    />';
    
       if ($description) echo '
     
    <meta
       name="description"
       content="', $description, '"
    />';
    
    echo '
    
    <link
       type="text/css"
       rel="stylesheet"
       href="', ROOT_HTTP, 'theme/screen.css"
       media="screen,projection,tv"
    />
    
    <title>
       ', ($pageTitle ? $pageTitle . ' - ' : ''), ' Site Title
    </title>
    
    </head><body>
    
    <div id="top" class="widthWrapper">
    
       <h1>
         Site Title
         <span><!-- image replacement --></span>
       </h1>
    
       <ul id="mainMenu">
         <li><a href="', ROOT_HTTP, '">Home</a></li>
         <li><a href="', ROOT_HTTP, 'articles">Articles</a></li>
         <li><a href="', ROOT_HTTP, 'about">About</a></li>
         <li><a href="', ROOT_HTTP, 'contact">Contact</a></li>
       </ul>
    
       <hr /><!-- remove if content starts with numbered heading -->
    
       <div id="contentWrapper"><div id="content">';
       // using double-wrapper for fluid content-first columns
     
    } // template_header
    
    function template_footer($extrasFile = false) {
       echo '
       <!-- #content, #contentWrapper --></div></div>
     
       <div id="extras">';
     
       // any static / common to all pages sidebar stuff here
     
       if ($extrasFile) include($extrasFile . '.php');
     
       echo '
       <!-- #extras --></div>
     
       <div id="footer">
         Disclaimer / Other footer stuff here
       <!-- #footer --></div>
     
    <!-- #top.widthWrapper --></div>
         ';
    } // template_footer
    
    ?>
    
    Code (markup):

    References for the code I'm using
     
    Solved! View solution.
    Puntocom81, Aug 3, 2016 IP
  2. Puntocom81

    Puntocom81 Banned

    Messages:
    80
    Likes Received:
    3
    Best Answers:
    1
    Trophy Points:
    35
    #2
    This code finds the requested article scanning the directory and comparing the title. Is there a better way to do this without SQL? I'm afraid of bad performance when the number of articles is high.

    Please sorry for the bad indentation, when copying the content to this editor the lines appear misplaced.

    statics/article.php
    
    <?php require_once('theme/index.template.php'); template_header(
       false, // don't show "pageTitle - Site title"
       'seven,or,eight,words,that,exist,in,body', // keywords
       'A short natural language description describing the site'
    ); require_once('libs/articles.lib.php');
      require_once('libs/paginate.lib.php');
    
    $number_of_articles = newsNumber();
    $number_of_pages = ceil($number_of_articles / 5);
    
    $articles=scandir($article_dir,1);
    $t=0;
    $found=0;
    
    while (!$found &&
      $t < $number_of_articles 
      ) {
       list($id,$date,$subject,$author)=explode('_',$articles[$t]);
      $slug = str_replace(' ', '_', strtolower($subject));
      if ($slug == request::value(1))
      $found++;
      $t++;
      }
    
    if (!$found) {
      echo '<h1>Error 404</h1>';
      http_response_code(404);
      template_footer();
      die();
    } else {
      if ($t == $number_of_articles)  // Sucky solution but it fixes a bug displaying the last article.
      $t--; 
      $slug = str_replace(' ', '_', strtolower($subject));
      $contents=str_ireplace($txt_convert['in'],$txt_convert['out'],
      trim(file_get_contents($article_dir.'/'.$articles[$t]))
      );
      echo '
      <div class="article">
      <h3>
      ',$subject,'
      </h3>
      <div class="article_body">
      ',$contents,'
      <div class="author">Author: ',$author,'</div>
      </div>
      </div>
      ';
    }
    
    template_footer(); ?>
    
    Code (markup):
    I have to fix details such as unique keywords & description for each article and clean up the code. Apart from that I'm happy with the results, I was using wok static generator and now I feel more free with PHP.
     
    Last edited: Aug 3, 2016
    Puntocom81, Aug 3, 2016 IP
  3. #3
    A legitimate concern, which can be slightly alleviated if you do something like break down months into their own subdirectories, but depending on your traffic levels that can very quickly result in diminishing returns if you post a LOT of date sorted articles.

    ScanDIr and glob both start to fall apart on high traffic levels in that regard -- and WHEN that becomes a concern, that's when you stop using a poor man's setup, bite the bullet, and dive into PHP.

    Poor man's is perfect for static page websites, but when it turns into a blog if you end up with a LOT of entries that you're sorting by date? That's when you'll start to have problems.

    You could use an intermediate step of a static file containing the directory entries as your own sort of "index", keeping say... 12 or so entries per file as a per-line item, but sooner or later you might have to man-up and use a database.

    Poor man's has it's flaws -- and while you CAN use it for a blog type system, it's really more of a education tool in that regard than a practical system. Eventually you do reach the point where it's time to put on the big boy pants.

    Again though, if all you have are static pages, it's bloody brilliant.

    NOT that adding a database to it is rocket science...

    Oh, and for the love of Christmas, if you have multiple echo in a row, only use one echo!
     
    deathshadow, Aug 3, 2016 IP
    Puntocom81 likes this.
  4. Puntocom81

    Puntocom81 Banned

    Messages:
    80
    Likes Received:
    3
    Best Answers:
    1
    Trophy Points:
    35
    #4
    I'm very happy exploring PHP, it's much more powerful and pleasant than messing with frameworks or static site generators. I have cleaned the code a little and I've also corrected a bug in statics/article.php. It's now adapted to utf-8.

    Although I still need to polish the code, the basic functionality is working fine for now :)

    statics/article.php
    
    <?php
    
    require_once('libs/articles.lib.php');
    require_once('libs/paginate.lib.php');
    
    $number_of_articles = newsNumber();
    $number_of_pages = ceil($number_of_articles / 5);  // 5 articles per page
    
    $articles=scandir($article_dir,1);
    $t=0;
    $found=0;
    
    while (!$found &&
      $t < $number_of_articles
      ) {
      list($date,$subject,$author)=explode('_',$articles[$t]);
      $slug = str_replace(' ', '_', strtolower($subject));
      if (friendize_url(utf8_encode($slug)) == request::value(1))
      $found++;
      $t++;
      }
    
    if (!$found) {
      require_once('theme/index.template.php');
      not_found(); // 404 error.
    
    } else {
    
      $slug = str_replace(' ', '_', strtolower($subject));
      $contents = explode('<!-- | -->',str_ireplace($txt_convert['in'],$txt_convert['out'],
      trim(file_get_contents($article_dir.'/'.$articles[$t-1])))
      );
      $author = str_replace('.article.txt','',$author);
    
      isset($contents[2]) ? $keywords=$contents[2] : $keywords=false;
      isset($contents[3]) ? $description=$contents[3] : $description=false;
    
      require_once('theme/index.template.php'); template_header(
      utf8_encode($subject), // if isset show "pageTitle - Site title"
      $keywords, // if isset show keywords
      $description
      );
      echo '
      <div class="article">
      <h2>
      ',utf8_encode($subject),'
      <br>
      <small>
      por ',utf8_encode($author),'
      </small>
      </h2>
      <div class="article_body">
      ',$contents[0].$contents[1],'
      </div>
      </div>
      ';
    }
    
    template_footer(); ?>
    
    Code (markup):
    libs/url.lib.php
    
    <?php
      function friendize_url($url) {
        $unwanted_array = array('Š'=>'S', 'š'=>'s', 'Ž'=>'Z', 'ž'=>'z', 'À'=>'A', 'Á'=>'A', 'Â'=>'A', 'Ã'=>'A', 'Ä'=>'A', 'Å'=>'A', 'Æ'=>'A', 'Ç'=>'C', 'È'=>'E', 'É'=>'E',
        'Ê'=>'E', 'Ë'=>'E', 'Ì'=>'I', 'Í'=>'I', 'Î'=>'I', 'Ï'=>'I', 'Ñ'=>'N', 'Ò'=>'O', 'Ó'=>'O', 'Ô'=>'O', 'Õ'=>'O', 'Ö'=>'O', 'Ø'=>'O', 'Ù'=>'U',
        'Ú'=>'U', 'Û'=>'U', 'Ü'=>'U', 'Ý'=>'Y', 'Þ'=>'B', 'ß'=>'Ss', 'à'=>'a', 'á'=>'a', 'â'=>'a', 'ã'=>'a', 'ä'=>'a', 'å'=>'a', 'æ'=>'a', 'ç'=>'c',
        'è'=>'e', 'é'=>'e', 'ê'=>'e', 'ë'=>'e', 'ì'=>'i', 'í'=>'i', 'î'=>'i', 'ï'=>'i', 'ð'=>'o', 'ñ'=>'n', 'ò'=>'o', 'ó'=>'o', 'ô'=>'o', 'õ'=>'o',
        'ö'=>'o', 'ø'=>'o', 'ù'=>'u', 'ú'=>'u', 'û'=>'u', 'ý'=>'y', 'þ'=>'b', 'ÿ'=>'y',' '=>'_' );
        return(strtr($url, $unwanted_array));
    }
    
    ?>
    
    Code (markup):
    I still have to generate 404 errors for every non-existant page in the site to avoid duplicate content issues.
     
    Last edited: Aug 5, 2016
    Puntocom81, Aug 5, 2016 IP
  5. PoPSiCLe

    PoPSiCLe Illustrious Member

    Messages:
    4,623
    Likes Received:
    725
    Best Answers:
    152
    Trophy Points:
    470
    #5
    The url-solution is really bad. First of all, you should do a strtolower() - there is never a valid reason to use caps in a link.
     
    PoPSiCLe, Aug 5, 2016 IP
    Puntocom81 likes this.
  6. mmerlinn

    mmerlinn Prominent Member

    Messages:
    3,197
    Likes Received:
    818
    Best Answers:
    7
    Trophy Points:
    320
    #6
    Not sure what you mean here. I checked some links on the net and when I changed them from caps to lc or vice versa, I get 404 errors OR the wrong page.
     
    mmerlinn, Aug 6, 2016 IP
  7. PoPSiCLe

    PoPSiCLe Illustrious Member

    Messages:
    4,623
    Likes Received:
    725
    Best Answers:
    152
    Trophy Points:
    470
    #7
    Yes... which is my point. All links should always be in lower case. Especially on your own site. Hence, you have a url-replacement array that contains values for caps - which shouldn't be needed, if the string you're doing the replacement on is already in all lower-case.

    Again, there shouldn't ever be a need to use caps in an URL - apart from maybe if you're uploading files, but still, you can just do a strtolower on the filename before it gets attached to the url, and placed in the file-system. However, you will then lose the ability to have different files with different type in the name - on filesystems where you can make such distinctions - ie, that there is a difference between ThisIsAFile.txt and thisisafile.txt.

    Hence my point that you shouldn't be needing the array-replacement. Also, that using such a replacement array is bound to fail, since you can't possibly cater for all potential valid filename characters. That's why you should use one of the built-in PHP functions instead, if the goal is to make normalised urls.
     
    PoPSiCLe, Aug 6, 2016 IP
  8. ThePHPMaster

    ThePHPMaster Well-Known Member

    Messages:
    737
    Likes Received:
    52
    Best Answers:
    33
    Trophy Points:
    150
    #8
    If you have access to Apache, you can enable mod_spelling. There is a tiny performance overhead, but wouldn't worry about it unless you have a famous website. Doing so will allow you to use both capital/lowercase without worrying.
     
    ThePHPMaster, Aug 7, 2016 IP
  9. Puntocom81

    Puntocom81 Banned

    Messages:
    80
    Likes Received:
    3
    Best Answers:
    1
    Trophy Points:
    35
    #9
    Thank you all for the replies.

    I run nginx but anyway I prefer lowercase urls. This function is a fix for some special characters in the article titles. I already do strtolower in another part of the code. I'll move it to this function for better organization.

    What I find more difficult is to adapt the pagination library to count from 1 instead of starting from zero. Also, both / and /0 give the same contents. My programming experience is very limited and I get lost in this algorithm.
     
    Last edited: Aug 7, 2016
    Puntocom81, Aug 7, 2016 IP
  10. deathshadow

    deathshadow Acclaimed Member

    Messages:
    9,732
    Likes Received:
    1,998
    Best Answers:
    253
    Trophy Points:
    515
    #10
    That's why you make it count from zero... *** counting from one on the back end or the URI.
     
    deathshadow, Aug 19, 2016 IP
  11. Puntocom81

    Puntocom81 Banned

    Messages:
    80
    Likes Received:
    3
    Best Answers:
    1
    Trophy Points:
    35
    #11
    Thank you for the tip. I have this modification in my TODO list with low priority... I'm learning many things in parallel: writing, html, css and php basics.

    Both http://cutcodedown.com/ and /blogSummary/0 (also /blogSummary) have exactly the same contents, is it a problem? especially taking into account that both URLs are linked inside the site.

    Next thing I want to try is to make a basic shopping cart since all existing solutions are bloated, so I'm going to start learning PDO with sqlite and php sessions. Some times people ask me for an online shop but I refuse to use things like prestashop or magento, so learning this apart from useful is a great opportunity to improve my programming skills.
     
    Last edited: Aug 22, 2016
    Puntocom81, Aug 22, 2016 IP
  12. deathshadow

    deathshadow Acclaimed Member

    Messages:
    9,732
    Likes Received:
    1,998
    Best Answers:
    253
    Trophy Points:
    515
    #12
    It's generally minor as it's an index of articles not the articles themselves, with both being variable content so I could give a flying **** if that page gets de-ranked compared to the ACTUAL article pages. Hence my use of rel="bookmark" on the title and read more links.

    If it were an actual issue, I'd use <link rel="canonical"> in the header of the "/" version.
     
    deathshadow, Aug 22, 2016 IP
    Puntocom81 likes this.