如何处理AJAX请求、会话和数据库连接


How to handle AJAX requests and Sessions and Db connections?

好的,我知道描述这个场景的最好方法是先给出这个例子:

假设我有一个名为index.php;

的页面

<html> 标签的最上面,可以找到;

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

<body> 标签内,可以找到:

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

现在在ajax.php页面中,有一个按钮,当单击该按钮时将发出ajax请求。发出请求后,将执行一个简单的Db查询语句,根据user_id选择用户信息。问题是,在AJAX请求之后,似乎user_id会话和已经包含的Db连接是"丢失"的。

我知道我可以使用条件语句来检查AJAX请求,只需添加行…

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

. .在ajax.php页面的顶部,但我想知道是否有更好的方法来做到这一点?我不想每次都给每个ajax PHP页面添加这两行代码。它有点违背了在母版页(index.php)上开始的目的。我想我可以使用一个ajax调用页面,只是包括一堆的情况下的声明,但仍然想知道是否有一个更好的方法。

非常感谢。

就我的经验而言,我认为你的问题可以用FrontController模式来解决。

基本思想是,您的整个应用程序总是调用相同的文件,例如index.php(也称为单点入口)。

index.php然后在每个页面上执行所需的所有任务(如启动会话或包含库类),然后调用您想要请求的页面。

这可能看起来像这样:(现在无法测试)

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!" />';

ajaxRequest() Javascript函数必须发送一个Ajax请求到index.php设置参数
Request_Type = 'ajax'
Ajax_Function = 'ProcessButton'

我不认为有更好的方法,但这并不意味着没有更好的方法。

从你的问题中得到一些提示:1)使用包装文件的所有头信息。所以,在页面的开头,放上:

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

然后在package中,我有:

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

这样,你所有的页面都在访问相同的东西。如果您需要更改它,它会容易得多。

require_once、include_once、include和require之间的速度是不同的。我不知道这有多重要。框架在制作一个页面时会包含60多个文件,所以我一直认为这不是太糟糕。

会话信息存储在服务器上的一个文件夹中。PHP默认为/tmp(您应该将其更改为私有文件夹/不可web访问)。

确保您正在验证发送到AJAX的任何信息。请记住,它就像它自己的网页一样,所以任何权限或数据库敏感信息都应该受到同样的保护。

"我想我可以使用一个ajax调用页面,只是包括一堆的情况下的声明,但仍然想知道是否有一个更好的方法。"

控制器模式非常适合这种类型的东西。在一个文件中有一堆case语句对您的维护很困难。当你的文件中只包含1到2个函数时,你的生活会变得简单得多。

根据项目的大小,您可能需要实现一个框架。查看MVC框架。如果我不实现一个框架,我仍然实现一个控制器模式。

我从我的博客上摘抄了这个。我现在用的甚至不像这样,但它从这里开始:

在表示层中,我决定要实现哪些元素。对于我想实现的每个元素,我初始化控制器,如下所示:

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

我正在使用由Matt Zandstra编写的PHP对象、模式和实践第三版控制器,并进行了自己的修改。

结果如下:

  1. 我的表示层得到一个新的控制器对象。
  2. Controller对象的构造函数自动创建一个新的CommandContext对象。
  3. CommandContext是自动将加载请求变量作为参数,所以我甚至不需要担心表单数据,直到我到达逻辑层,需要验证和处理它。
  4. 在表示层,我加载任何额外的上下文参数(或我想传递给控制器的信息),包括最重要的,我想让控制器采取的动作。为了传递信息,我调用$controller->process()。在逻辑层,我可以使用默认的"执行"或创建不同的命令。因此,在表示层中,我将动作设置为"Login",这将强制打开登录命令和登录视图页面,并且命令默认执行,但它可以是任何东西。当我调用process时,它会触发commandfactory。CommandFactory将首先初始化一个新的Template子对象,比如一个边栏div框或主体上下文。它通过一个可选的标志来做这个决定,我可以把这个标志传递给控制器。然后CommandFactory将打开命令文件并将模板和上下文作为对象传递给逻辑层。
    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();
            }
        }
    }

逻辑层在固定目录下。控制器层已经创建了对象的实例,这意味着构造函数已经被触发。此外,控制器层已经调用了方法"execute"(默认)或其他方法,例如"getLoginForm"。另外,请注意,当控制器调用"execute"方法时,它也将CommandContext传递给该方法,因此我们有东西可以使用。

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;    
    }
}

你看起来很困惑。

AJAX请求是对网页的单独请求,您在服务器端的index.php中所做的任何操作都不会在后续请求中可用(会话中的任何变量除外)。它是这样工作的:

  1. 从浏览器向index.php发送请求
  2. 服务器运行index.php(在会话中存储user_id)并在结束时返回HTML输出给浏览器,PHP脚本完成,所有资源被释放。
  3. 用户点击按钮,创建一个新的请求另一个PHP文件,比如ajax.php
  4. 服务器运行ajax.php并返回任何输出到浏览器。PHP脚本再次完成,所有资源被释放。

从另一个角度考虑这个问题:从服务器端来看,AJAX请求几乎就像您将浏览器直接指向AJAX .php一样。