【问题标题】:How to handle AJAX requests and Sessions and Db connections?如何处理 AJAX 请求以及 Sessions 和 Db 连接?
【发布时间】:2012-01-30 11:53:00
【问题描述】:

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

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

<html>标签之前的最顶端,可以找到;

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

&lt;body&gt;标签里面,可以找到:

<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 页面的顶部,但我想知道是否有更好的方法来做到这一点?我不想总是将这两行添加到每个名为 PHP 的 ajax 页面中。它有点违背了在母版页 (index.php) 上开始使用这些行的目的。我想我可以使用一个名为 page 的 ajax 并只包含一堆 case 语句,但仍然想知道是否有更好的方法。

非常感谢。

【问题讨论】:

  • "问题是,在 AJAX 请求之后,user_id 会话和已经包含的 Db 连接似乎“丢失”了。"你能解释一下“迷失”是什么意思吗?
  • 例如:致命错误:在 %directory%\ajax.php 页面中找不到类 'DbQuery',其中 DbQuery 是 mysql 查询的类的名称。基本上,在发出 AJAX 请求后,不会找到或“丢失”此类文件(如 db.con.php)中定义的任何类或函数。非常感谢。
  • 您是否在 [%directory%\ajax.php] 中包含了 [require_once "db.con.php";] ?
  • 加载 Ajax 请求就像您完全进入了一个新网页一样。所以是的,它是“丢失”的。这是一个新的 HTTP 请求。

标签: php mysql ajax session


【解决方案1】:

就我的经验而言,我认为您的问题可以通过 FrontController pattern 来解决。

基本思想是整个应用程序总是调用同一个文件,例如 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 函数必须向 index.php 发送一个 Ajax 请求来设置参数
Request_Type = 'ajax'
Ajax_Function = '进程按钮'

【讨论】:

  • 谢谢。这种设计模式确实解决了这个问题。我感谢所有的回应,尤其感谢被指出这些设计模式。他们将在所有未来的项目中派上用场。谢谢大家!
【解决方案2】:

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

阅读您的问题后的几点说明: 1) 对所有标题信息使用包装文件。所以,在页面的开头,输入:

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

然后在包装中,我有:

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

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

require_once、include_once、include和require之间存在速度差异。我不知道它有多重要。框架在制作页面时包含大约 60 多个文件,所以我一直认为它还不错。

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

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

“我想我可以使用一个名为 page 的 ajax 并只包含一堆 case 语句,但仍然想知道是否有更好的方法。”

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

根据您的项目规模,您可能希望实施一个框架。查看 MVC 框架。如果我不实现框架,我仍然会实现控制器模式。

我从我的博客中删除了这个。我现在用的根本不是这个样子,而是从这里开始的:

在表示层中,我正在确定要实现哪些元素。对于我想要实现的每个元素,我都会启动控制器,如下所示:

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

我正在使用来自 Matt Zandstra 的 PHP Objects, Patterns, and Practice 3rd Ed 的控制器,并进行了我自己的修改。

会发生什么:

  1. 我的表示层获得了一个新的控制器对象。
  2. Controller 对象的构造函数自动创建一个新的 CommandContext 对象。
  3. CommandContext自动将请求变量作为参数加载,所以我什至不需要担心表单数据,直到我到达逻辑层并需要验证和处理它。
  4. 在表示层中,我加载了任何其他上下文参数(或我想要传递给控制器​​的信息),包括最重要的,我希望控制器执行的操作。
  5. 为了传递信息,我调用$controller->process()。在逻辑层,我可以使用默认的“执行”或执行不同的命令。因此,在表示层中,我将操作设置为“登录”,这会强制登录命令和登录视图页面打开,并且该命令默认为执行,但它可以是任何东西。
  6. 当我调用进程时,它会触发 CommandFactry。 CommandFactory 将首先启动一个新的 Template 子对象,例如侧栏 div 框或主体上下文。它使用我可以传递给控制器​​的可选标志来做出此决定。
  7. 然后,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”。另外,请注意,当 Controller 调用方法“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;    
    }

}

【讨论】:

  • 谢谢!在 MVC 上做一些阅读。我找到了一些链接,其中包含一些看起来很有帮助的文章:Link 1Link 2..如果你有的话,你可以给我指点更多。 :)
【解决方案3】:

你看起来很困惑。

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

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

另一种思考方式:从服务器端,AJAX 请求几乎与您直接将浏览器指向 ajax.php 相同。

【讨论】:

  • 谢谢。我对这些回答并不感到惊讶,但是提出这个问题可以让其他人向我指出 MVC。虽然我在 WP 代码中看到过,但我意识到学习设计模式可能是值得的。我会给你们两个都投赞成票,但我刚加入董事会。所以我能做的就是说声谢谢! :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-12-04
  • 2010-09-06
  • 1970-01-01
  • 2013-01-31
  • 2014-01-07
  • 1970-01-01
相关资源
最近更新 更多