【问题标题】:PHP $_SESSION variables not working in ionic/angularjs applicationPHP $_SESSION 变量在 ionic/angularjs 应用程序中不起作用
【发布时间】:2019-06-05 04:33:31
【问题描述】:

开发环境信息:

  • 本地开发
  • 在我的 PC 上设置我的服务器的网络驱动器
  • 通过目录路径访问服务器文件
  • 服务器包含 SQL 数据库,服务器文件可以访问和从中访问

在应用程序加载时

我已经在我的页面上设置了 ng-init 来运行函数$scope.nginit();,它会向我的名为 login.php 的服务器文件发送 $_GET 请求:

$http.get(url + "server/login.php", 
            { transformResponse: [] })
.success(function(data, status, headers, config) 
{
    data = JSON.parse(data);
    window.localStorage.setItem("session_id",data.session_id);
})
.error( function(data, status, headers, config) 
{
    console.log("Error: " + data + "; " + status);
});

这包含在页面顶部的每个服务器文件中:

// if(isset($_GET['session_id'])) {
//  session_id($_GET['session_id']);
// } else if(isset($_POST['session_id'])) {
//  session_id($_POST['session_id']);
// }

session_start();

include_once "../scripts/masterscript.php";

header("Access-Control-Allow-Origin: *");

$connection = connect_to_database();
try
{
    if($_SERVER['REQUEST_METHOD'] != 'POST')
    {
        setup_form();
    }
    else
    {
        process_form();
    }

    sqlsrv_close($connection);  
}
catch (Exception $e)
{
    exit("Exception $e->getMessage()");
}

这里是 login.php 上的 setup_form():

function setup_form()
{
    global $connection;
    header('Content-Type: application/json');
    $user_data = array();

    $user_data["session_id"] = session_id();

    echo json_encode($user_data);   
}

在 submitForm() 上;用于登录:

它将存储在 localStorage 中的 session_id 添加为参数,以便可以将其设置回 PHP 会话。它将它设置在 PHP 文件的顶部,但该部分目前已被注释掉。

我的意图是如果它是管理员用户,然后运行第二个 $http.request 并打开一个模式。

$http.post(url + "pages/login.php", data_string,
            {   headers: {'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8;' }, 
                params : { 'session_id' : window.localStorage.session_id }})
.success(function(data, status, headers, config) 
{
    var data = data[0];

    if(data.is_admin)
    {
        $http.get(url + "server/get_more_info.php", 
                    { params : {'user_id' : data.user_id },
                    transformResponse: [] })
        .success(function(data, status, headers, config) 
        {
            // setup to open a modal
        })
        .error( function(data, status, headers, config) 
        {
        }); 
    }
})
.error( function(data, status, headers, config) 
{
});

因为它是一个 $_POST 请求,所以它会转到 process_form(),这里是:

function process_form()
{
    global $connection;
    header('Content-Type: application/json');
    $user_data = array();

    $data_string = file_get_contents("php://input");
    $data = json_decode($data_string);

    $user_data['status_msg'] = "Error";

    // runs SQL query, grabs user details where email = $data->email
    $UserObj = new User(0,$connection, $data->email); 

    if($UserObj->password == $data->password)
    {
        $user_data['status_msg'] = "OK";
        $user_data['user_id']    = $UserObj->user_id;
        $user_data['user_type'] = $UserObj->user_type;

        if($UserObj->admin_user == 1)
        {
            $user_data['is_admin'] = true;
            $_SESSION['is_admin'] = 1;
        }

        $_SESSION['user_id'] = $UserObj->user_id;
        $_SESSION['user_type'] = $UserObj->user_type;
    }

    unset($UserObj);
    echo json_encode($user_data);
 }

在 get_more_info.php 中

我尝试访问 login.php 中设置的会话变量,但它们是空白的。我打算在 SQL 查询中使用这些变量:

$user_id = $_SESSION['user_id'];
$admin_user = $_SESSION['admin_user'];
$user_type = $_SESSION['user_type'];

$sql = " select * from info_table where admin_user = ? and user_type = ?";
$params = array($admin_user,$user_type);
$result = sqlsrv_query($connection, $sql, $params);       

while($row = sqlsrv_fetch_array($result, SQLSRV_FETCH_ASSOC))
{
}

sqlsrv_free_stmt($result);
unset($result);

额外信息

我做了一个 var_dump();对于下面这两个并返回空字符串。

ini_get('session.cookie_httponly');
ini_get('session.cookie_secure');

在 Firefox 上,出现了 login.php 的第一个网络请求,即 GET 请求,并设置了 $_COOKIE。似乎它适用于chrome,但不适用于firefox。我目前正在运行ionic serve --lab。在 chrome 上它会继续并打开一个模态,但在 Firefox 上它不会。

在 login.php GET 请求的 Firefox 的网络选项卡上,它显示 响应标头下的 set-cookie,但请求标头上没有与 cookie 相关的属性。

对于 login.php POST 请求,它与之前的 cookie 具有相同的结果,但此请求在网络选项卡下显示为 OPTIONS 方法,而不是 POST

问题

  • 最初的问题是get_more_info.php 中的会话变量为空。这是因为它没有恢复到从 $scope.nginit(); 开始的同一会话。相反,它正在开始一个新的。
  • 提出了存储 session_id 以便可以恢复到同一会话的想法,这就是我在这里所做的。
  • 最初我试图通过在我的 PHP 文件顶部手动设置 session_id 来设置它,但我注意到这不是必需的,它应该自动执行它不是。

【问题讨论】:

  • 你已经分配了 $UserObj->user_id;到会话并分配 $UserData->user_id;到用户数据。那样可以么。尝试使用本地存储
  • @Chrisshi $user_data['user_id'] = $UserObj->user_id 是从服务器传递的内容,然后可以通过客户端的data.user 访问。 localstorage 只能在客户端使用,我试图在服务器端使用$_SESSION 变量来持久访问user_id,而不是每次执行$http.post 或@987654340 时都将user_id 作为参数传递@.
  • 您可以在注册时生成一个令牌,并将该令牌为用户存储在表中。使用该令牌,您可以访问用户的帐户
  • @cbaconnier 我已经更新了我的问题以包含潜在的修复。我不知道您将其传递给标题是什么意思。我尝试通过 http.get/post 进行操作,但无法使其正常工作,因此我通过 http 参数传递了它们。您对我的解决方案提到的内容有什么不同?你有我可以看的例子,以便我能理解你的意思吗?

标签: javascript php angularjs session


【解决方案1】:

后端

首先:这一点是不必要的

if(isset($_GET['session_id'])) {
    session_id($_GET['session_id']);
} else if(isset($_POST['session_id'])) {
    session_id($_POST['session_id']);
}

more_details.php 文件开头需要的唯一行是session_start()

如果您查看the documentation for this function,它清楚地表明:

session_start() 创建一个会话或恢复 (*) 基于通过 GET 或 POST 请求或通过 cookie 传递的会话标识符的当前会话。

* 强调我的

所以调用它之后,就可以安全地访问$_SESSION 属性了。

其次,您需要设置正确的 CORS 标头。

header("Access-Control-Allow-Origin: http://localhost:8000");
header("Access-Control-Allow-Headers: content-type, authorization");
header("Access-Control-Allow-Credentials: true");

非常重要Access-Control-Allow-Origin 不能设置为 *,否则会失败。使用credentials时,需要明确设置允许的来源。

此外,您需要考虑一个 OPTIONS 调用,它应该返回相同的标题。此调用将由浏览器在 POST 请求之前作为飞行前验证进行。

出于此答案的目的,我有一个 common.php 文件:

<?php
session_start();
header( "Access-Control-Allow-Origin: http://localhost:8000" );
header( 'Content-Type: application/json' );
header( "Access-Control-Allow-Headers: content-type,authorization" );
header( "Access-Control-Allow-Credentials: true" );

if ( $_SERVER['REQUEST_METHOD'] == 'OPTIONS' ) {
    die();
}

另一个文件one.php

<?php
// one.php
<?php
require 'common.php';

$was_session_set     = $_SESSION['user_id'] ?? 'no session id yet';
$_SESSION['user_id'] = microtime( true );

echo '{"session": "' . $was_session_set . '"}';

die();

另一个两个.php

<?php
require 'common.php';

$user_id = $_SESSION['user_id'] ?? 0;
echo '{"session": "' . $user_id  .'"}';

die();

前端

let app = angular.module('myApp', []);
app.controller('myCtrl', function ($scope, $http) {
$http.get("http://localhost:8006/one.php",  { withCredentials: true })
    .then(function (response) {
      $scope.myWelcome = response.data;
      $http.post("http://localhost:8006/two.php", { withCredentials: true })
          .then(function (response2) {
            console.log(response2.data);
          })
    });
});

【讨论】:

  • 感谢您的回答。我刚刚删除了文件顶部 session_id 的手动设置,但它现在停止工作。当我运行 http.get 请求并通过参数$http.get(url + "server/get_more_info.php", { params : {'session_id' : window.localStorage.session_id}, transformResponse: [] }) 传递它时,我正在传递 session_id。它如何知道将哪个参数应用于 session_id?我需要将参数键更改为特定的吗?
  • @yivi 这完美!我已经将它与用户/msphn 的回答结合起来,这样我就不必为每个请求输入 withCredentials:true 了。
  • @J.Do 那是你的选择。我宁愿明确说明这一点,这样您就可以确切地知道哪些请求需要这些额外信息。否则,您可能会在不需要这种设置的请求中遇到 CORS 问题。
  • @yivi 明白了。谢谢你。还有一件事,我设置了header( "Access-Control-Allow-Origin: http://localhost:8000" );。主机端口是每次都一样还是会改变?
  • @J.Do 主机和端口 应该匹配你在哪里提供 Angular 应用程序。在此示例中,我使用 localhost:8000 因为这是我用于本地设置的内容。如果您将其部署在不同的域或端口中,则允许来源应与 that 匹配。
【解决方案2】:

要使用 cookie(这是 php 会话所必需的),您需要告诉您的应用允许它。

使用它来全局配置它,之后应用程序将使用您的 cookie 并将其重用于其他请求。

.config(['$httpProvider', function($httpProvider) {
   $httpProvider.defaults.withCredentials = true;
}])

【讨论】:

  • 我已经尝试过了,我现在收到错误 Access to XMLHttpRequest at 'hostserver/server_files/pages/login.php' from origin 'localhost:8100' has been blocked by CORS policy: Response to preflight request doesn't通过访问控制检查:当请求的凭证模式为“包含”时,响应中的“Access-Control-Allow-Origin”标头的值不能是通配符“*”。 XMLHttpRequest 发起的请求的凭证模式由 withCredentials 属性控制。
  • 是的,第一个请求是 OPTIONS 类型的,询问服务器的期望。之后发送实际请求。 OPTIONS 请求不允许在 allow-origin 中使用通配符。所以 OPTIONS 请求只响应一个具体而不是列表,即使您解析请求并决定要返回哪个请求。你可以例如检查主机列表,如果请求主机在此列表中,则返回与此主机完全相同的标头。
  • @J.Do 在我的回答中,我解决了 OPTIONS 电话。这是浏览器执行的飞行前调用。您需要正确响应此请求。您还需要发回正确的 CORS 标头,正如我在回答中显示的那样。
猜你喜欢
  • 2017-10-31
  • 1970-01-01
  • 2014-03-31
  • 2023-03-11
  • 1970-01-01
  • 2021-07-25
  • 1970-01-01
  • 2016-02-02
  • 2016-11-23
相关资源
最近更新 更多