Welcome Guest, Not a member yet? Register   Sign In
[library] History
#1

[eluser]Peter Goodman[/eluser]
This library provides an easy way to properly deal with history events. It only keeps track of unique history events and allows the programmer to exclude actions or controllers from within any controller.

/libraries/History.php
Code:
<?php

/**
* Simple class for dealing with the history. This class pushes and pops the urls of
* the pages that the user has visited onto a stack in the session. This allows us
* to exclude certain pages, eg: login/out, pages with POST data, etc. from the stack
* so that we end up with a more dependable way of navigating to previous pages then
* using $_SERVER['HTTP_REFERER']
* @author Peter Goodman
* @copyright Copyright 2007 Peter Goodman, all rights reserved.
*/
class History {
    private $exclude = FALSE;
    private $session;
    private $history = array();
    
    /**
     * Constructor, set up the stack if it doesn't exist.
     * @internal
     */
    public function __construct() {
                
        $this->session = get_instance()->session;
        
        // make sure the stack exists, first-in-last-out stack of
        // paths
        if(!$this->session->userdata('url_history')) {
            $this->session->set_userdata('url_history', array());
        }
        
        $this->history = $this->session->userdata('url_history');
                
        // make sure to do this, not necessarily necessary :P
        reset($this->history);
    }
    
    /**
     */
    public function __destruct() {
        unset($this->session);
    }
    
    /**
     * Push (actually unshift) a page onto the stack.
     */
    public function push($path) {
        if(!$this->exclude) {
                            
            // don't want duplicates
            if(current($this->history) != $path) {
                array_unshift($this->history, $path);
            }
            
            // we can safely use slice because we deal with un/shifting
            // and not pushing/popping. We slice to 5 pages so that the stack
            // is a manageable size
            $this->history = array_slice($this->history, 0, 5);
            
            // set the data
            $this->session->set_userdata('url_history', $this->history);
        }
    }
    
    /**
     * Pop (actually shift) a page off of the stack.
     */
    public function pop() {
        $url = array_shift($this->history);
        
        if(!$url) {
            $url = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : $_SERVER['PHP_SELF'];
        }
        
        return $url;
    }
    
    /**
     * Get the last (actually first) page off od the stack without
     * shifting it off.
     */
    public function end() {
        return isset($this->history[0]) ? $this->history[0] : (isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : $_SERVER['PHP_SELF'];
    }
    
    /**
     * Exclude a page from the stack.
     */
    public function exclude() {
        $this->exclude = TRUE;
    }
    
    /**
     * Clear out the history.
     */
    public function clear() {
        $this->history = array();
        $this->session->set_userdata('url_history', $this->history);
    }
    
    /**
     */
    public function export() {
        return $this->history;
    }
}

/hooks/history.php
Code:
<?php

// automatically load the history library before the
// controller action is executed and then automatically
// push the page into the history cache after the action
// has executed.

function setup_history() {
    $ci = get_instance();
    $ci->load->library('history');
}
function push_history() {
    $ci = get_instance();
    $ci->history->push($ci->uri->uri_string());
}

/config/hooks.php:
Code:
$hook['post_controller'] = array(
                                'function' => 'push_history',
                                'filename' => 'history.php',
                                'filepath' => 'hooks',
                                );
$hook['post_controller_constructor'] = array(
                                'function' => 'setup_history',
                                'filename' => 'history.php',
                                'filepath' => 'hooks',
                                );

Usage:
Code:
// exclude a page from history:
$this->history->exclude();

/*
pop a page off of the history stack, this is useful if you have something that needs to redirect to the previous page. When a page is popped off of the stack, it disappears from it.
*/
$prev_page = $this->history->pop();

// to redirect to the previous page:
redirect($this->history->pop());

/*
Sometimes it's useful to know the previous page but not to pop it off of the stack. If you have a step system and want to validate the page that brought you to somewhere, use end() as so:
*/
$prev_page = $this->history->end();
#2

[eluser]Phil Sturgeon[/eluser]
Nice one! I hope some of your changes get included, alot of useful things have been posted here.
#3

[eluser]Peter Goodman[/eluser]
Note to all PHP4 users: Making this php4 compatible is easy: remove all public/private/protected in front of function definitions. Remove all public/private/protected in front of class variable definitions (at the top of the class) and replace them with "var" Then, look for every "= get_instance()" and replace with "=& get_instance()"
#4

[eluser]Phil Sturgeon[/eluser]
Remove the public/private in front of function declarations too :p
#5

[eluser]Unknown[/eluser]
Very good thank you Smile
#6

[eluser]ACSparks[/eluser]
What kind of overhead is associated with using this history class?

Past pages are being stored in the session. Does this exist only in RAM or does each user have a session file on the server? If the session is a file on the server, wouldn't each page view correspond to a hard disk write?

Thanks!
#7

[eluser]Unknown[/eluser]
Hello,
thanx for this library!

but function pop in if(!$url) {... returns full url (http://domain.tld/ci/cont) else only something like "/cont" . When i use it in redirect($this->history->pop()); it jumps to http://domain.tld/ci/http://domain.tld/ci/cont (404)

I solved it by modifiing functions pop & end to:
Code:
public function pop() {
        $url = array_shift($this->history);
        if(!$url) {
            $url = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : $_SERVER['PHP_SELF'];
        }
        $url = preg_replace("|".base_url()."|", "/", $url);
        
        return $url;
    }
    public function end() {
        return preg_replace("|".base_url()."|", "/", isset($this->history[0]) ? $this->history[0] : (isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : $_SERVER['PHP_SELF']));
    }
(added preg_replace)

so HTTP_REFERER redirecting works well but i want to use $url = array_shift($this->history); not this

my question is why it cant use address from history and must use HTTP_REFERER. I dont know when it occurs, maybe something wrong with redirect($this->history->pop());

(btw codeigniter beginner..)


EDIT:
solved: Simplelogin deleted sessions data on every login/logout, so i lost my url history..
#8

[eluser]Dave S[/eluser]
This library is great! It's exactly what I was looking for.

I do have one question though, if I want to exclude a page from being added to the history, where do I put this line:

Code:
$this->history->exclude();

I tried placing it in the constructor of the controller, as well as in the index function, but it is still being added.

Thanks again!
#9

[eluser]Peter Goodman[/eluser]
You put in either the method itself (to exclude a method) or the controller's constructor (to exclude an entire controller). The easiest way to have it all working is to make your own controller extending CI's default one and in that constructor load up the history library (as well as calling the parent constructor). If this doesn't work, please reply here.
#10

[eluser]Dave S[/eluser]
Hmm... I did try it in the constructor but somehow it's still getting added.




Theme © iAndrew 2016 - Forum software by © MyBB