3

Okay, the best way I know to describe the scenario is to first give the example:

Say I have a page called index.php;

At the very top before the <html> tag, one can find;

<?php session_start();
 $_SESSION['user_id'] = 1234;
 require_once "db.con.php";
?>

Inside that of the <body> tag, one can find:

<div id="div_ajax">
<?php require_once "ajax.php"; ?>
</div>

Now inside the ajax.php page, there is a single button that when clicked will make an ajax request. After the request is made, a simple Db query statement to select user information based on the user_id will be made. The thing is, after the AJAX request, it seems as if the user_id session and the already included Db connection is "lost".

I know I can use a conditional statement to check for AJAX request and just add the lines...

session_start();
require_once "db.con.php";

..at the top of the ajax.php page, but I'm wondering if there's a better way to do this? I don't want to always have to add those two lines to every ajax called PHP page. It sort of defeats the purpose of having the lines on the master page (index.php) to begin with. I guess I can use one ajax called page and just include a bunch of case statements, but still wondering if there's a better way.

Thanks a lot.

Harvester316
  • 381
  • 1
  • 8
  • 17
  • "The thing is, after the AJAX request, it seems as if the user_id session and the already included Db connection is "lost"." Could you explain what do you mean by "is lost"? – Slavic Dec 30 '11 at 10:22
  • For instance: Fatal error: Class 'DbQuery' not found in %directory%\ajax.php page, where DbQuery is the name of a class for mysql queries. Basically, any classes or functions defined in such files like db.con.php are not found or "lost" after the AJAX request is made. Thanks a lot. – Harvester316 Dec 30 '11 at 10:33
  • Did you include [require_once "db.con.php";] in [%directory%\ajax.php] ? – Slavic Dec 30 '11 at 10:36
  • 1
    Loading an Ajax request is as if you had gone to a new web page entirely. So yes, it is "lost". It's a new HTTP request. – phpmeh Dec 30 '11 at 10:42

3 Answers3

1

I don't think that there is a better way, but that doesn't mean that there isn't.

Just a couple of notes from reading your question: 1) Use wrapper files for all of your header information. So, at the beginning of your page, put:

require_once('package.php'); // that's what I call mine

Then in package, I have:

require_once('session.start.php');
require_once('db.con.php');

That way, all your pages are accessing the same thing. If you ever need to change it, it's a lot easier.

There is a speed difference between require_once, include_once, include and require. I don't know how significant it is. Frameworks include like 60+ files when they make a page, so I've always assumed its not too bad.

The session information is stored in a folder on your server. PHP defaults it to /tmp (which you should change to a private folder / not web accessible).

Make sure that you are validating any information sent to the AJAX. Remember that it is just like its own web page, so any permissions or database sensitive information should be protected all the same.

"I guess I can use one ajax called page and just include a bunch of case statements, but still wondering if there's a better way."

The controller pattern is pretty good for this type of thing. Having a bunch of case statements in one file is hard on your maintenance. When you switch to having files that only have 1 or 2 functions in them, your life will get so much simpler.

Depending on the size of your project, you may want to implement a framework. Check out MVC frameworks. If I don't implement a framework, I still implement a controller pattern.

I lifted this from my blog. What I use now doesn't even look like this, but it started here:

In the Presentation layer, I am determining which elements I want to implement. For each element that I want to implement, I initiate the controller, like so:

    $controller = new Controller();
    $context = $controller->getContext();
    $context->addParam('action', 'login');
    $template->setContent( $controller->process() ); 

I am using the Controller from PHP Objects, Patterns, and Practice 3rd Ed by Matt Zandstra with my own modifications.

Here is what happens:

  1. My presentation layer gets a new controller object.
  2. The Controller object's constructor automatically creates a new CommandContext object.
  3. The CommandContext is automatically going to load up the request variables as a Parameter, so I don't even need to worry about form data until I get to the Logic layer and need to validate and process it.
  4. In the presentation layer, I load up any additional context parameters (or the information that I want to pass on to the controller), including most importantly, the action that I want to be taken by the Controller.
  5. To pass the information on, I call $controller->process(). In the Logic layer, I can use a default "execute" or make a different command. So, in the Presentation layer, I set the action to "Login" which forces the login command and login view pages to open, and the command defaults to execute, but it could be anything.
  6. When I call process, it triggers the CommandFacotry. The CommandFactory is going to first initiate a new Template child object, such as a side bar div box or main body context. It makes this determination with an optional flag that I can pass to the Controller.
  7. The CommandFactory is then going to open up the Command file and pass the template and the context as objects to the Logic layer.
    abstract class Command {

    }

    class CommandContext {
        private $params = array();
        private $error = "";

        function __construct(){
            $this->params = $_REQUEST;
        }

        function addParam( $key, $val ){
            $this->params[$key] = $val; 
        }

        function get( $key ){
            return $this->params[$key]; 
        }

        function issetCheck( $key ){
            if( ! empty( $this->params[$key] ) ){
                return true;
            }
            return false;
        }
        function setError( $error ){
            $this->error = $error;  
        }

        function getError(){
            return $this->error;    
        }
    }

    class CommandNotFoundException extends Exception { }

    class CommandFactory {
        private static $dir = 'include/classes/command/';

        static function getCommand( $action = 'Default', $flag = 0 ){

            switch( $flag ){
                case 1:
                    $template = new TemplateQuickViewOnly();
                    break;
                case 2:
                    $template = new TemplateQuickViewToggle();
                    break;
                default: 
                    $template = new TemplateMainBodyOnly();
                    break;
            }

            if( preg_match ( '/\W/', $action ) ){
                throw new Exception("illegal characters in action");    
            }

            $class = UCFirst(strtolower($action))."Command";
            $file = ROOT_PATH."".self::$dir."{$class}.php";
            if( ! file_exists( $file ) ){
                throw new CommandNotFoundException( "could not find '$file'" ); 
            }
            include_once( $file );
            if( ! class_exists($class) ){
                throw new CommandNotFoundException( "no '$class' class located" );  
            }
            $cmd = new $class( $template );

            return array( $cmd, $template );
        }
    }

    class Controller {
        private $context;

        function __construct(){
            $this->context = new CommandContext();
        }

        function getContext(){
            return $this->context;  
        }

        function process( $method = 'execute', $flag = 0 ){
            list( $cmd, $template ) = CommandFactory::getCommand( $this->context->get('action'), $flag );
            if( ! $cmd->$method( $this->context ) ){
                // handle failure
    //          $template->setMessage( UCFirst($this->context->get('action')).' failed to execute.');
                return $template->getMessage();
            }else{
                // success dispatch view
                return $template->getMessage();
            }
        }
    }

The Logic layer is in a fixed directory. An instance of the object has already been instatiated by the Controller layer, which means the constructor has been triggered. Further, the controller layer already called the method "execute" (default) or another method, such as "getLoginForm". Also, note that when the Controller calls the method "execute", it is also passing the CommandContext to the method so we have stuff to work with.

class LoginCommand extends Command {

    public function __construct( ){ }

    function execute ( CommandContext $context ){

        if( $context->get('login_user_name') == 'demo' ){
            $this->view->setMessage('Success is true!');
            return true;
        }
        return false;
    }

    function getLoginForm( CommandContext $context ){
        $this->view->setMessage('Second sucess is even more true!');
        return true;    
    }

}
phpmeh
  • 1,752
  • 2
  • 22
  • 41
  • Thanks! Doing some reading on MVC. I found some links with some helpful enough looking articles: [Link 1](http://www.phpro.org/tutorials/Model-View-Controller-MVC.html)[Link 2](http://php-html.net/tutorials/model-view-controller-in-php/)..maybe you can point me to some more if you have any. :) – Harvester316 Dec 30 '11 at 12:06
1

As far as my experience goes, I think your problem can be solved with something called the FrontController pattern.

The basic idea is that you're whole application always calls the same file, index.php for instance (also called the single point of entry).

index.php then performs all the tasks that you need on every single page (like starting the session or including your library classes) and then calls the page you want to requested.

This could look something like this: (Can't test it now)

index.php:

<?php

    session_start();
    $_SESSION['user_id'] = 1234;
    require_once("db.con.php");


    if($_REQUEST['Request_Type'] == 'website'){
        require_once("header.html");

        switch($_REQUEST['Request_Url']){
            case 'SomePage':
                require('SomePage.php');
                break;
            case 'SomeOtherPage':
                require('SomeOtherPage.php');
                break;
            default:
                require('ajax.php');
        }

        require_once("footer.html");

    }elseif($_REQUEST['Request_Type'] == 'ajax'){
        switch($_REQUEST['Ajax_Function']){
            case 'ProcessButton':
                require('ProcessButton.php');
                break;
        }
    }

?>

ajax.php

echo '<input type="button" onClick="ajaxRequest(\"index.php\",\"ProcessButton\")" Value="ClickMe!" />';

The ajaxRequest() Javascript function would have to send an Ajax Request to index.php setting the parameters
Request_Type = 'ajax'
Ajax_Function = 'ProcessButton'

Community
  • 1
  • 1
Envyrus
  • 315
  • 1
  • 3
  • 10
  • Thank you. This design pattern does indeed solve the problem. I appreciate all responses, especially appreciate being pointed to these design patterns. They will come in handy on all future projects. Thanks to you all! – Harvester316 Dec 31 '11 at 07:03
0

You seem confused.

AJAX requests are separate requests for a webpage, nothing you did in the index.php on the server side will be available in the subsequent requests (except for any variables in the session). It works like this:

  1. Request is sent for index.php from the browser
  2. Server runs index.php (storing user_id in the session) and returns the HTML output to the browser at the end, the PHP script finishes and all resources are freed.
  3. User clicks on button, creating a new request for another PHP file, say ajax.php
  4. Server runs ajax.php and returns whatever is output to the browser. Again the PHP script finishes and all resources are freed.

Another way to think about this: From the server side, an AJAX request is almost the same as if you'd just pointed your browser to ajax.php directly.

Ezequiel Muns
  • 7,492
  • 33
  • 57
  • Thanks. I am not surprised by the responses, but asking the question allowed someone else to point out MVC to me. Although I've seen it in WP code, I'm realizing that it is probably worth it to learn the design pattern. I'd give you both an up vote but I just joined the board. So most I can do is say thanks! :) – Harvester316 Dec 30 '11 at 12:15