首页 > 解决方案 > XHR 请求和下载禁止的解决方法

问题描述

我有一个奇怪的情况:我从 Postgres 数据库中获取数据,然后从这些数据中,我使用 Grid.js 在网站中创建了一个表。每行都有一个“下载”按钮,该按钮从该表条目中获取 2 个参数并将它们发送到一个函数。最初,该函数将向 php 文件发出 XHR 请求,该文件从另一个数据库获取文件,创建一个 ZIP 文件,并将其发送给用户,并使用readfile().

桌子

我现在发现这是不可能的。出于安全原因,XHR 不允许下载。我可以做一些事情window.location来调用 PHP 文件并获取下载,但是我正在处理数百个文件,所以我不能编写数百个 PHP 文件来单独获取数据。我可以,但是维护和管理所有这些文件会非常困难,而且感觉不专业。

现在,我可以:

我需要:

当前代码是:

const getData = (schema, table) => {

    const xhr = new XMLHttpRequest();

    xhr.open('POST', 'php/get_data.php', true);
    xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');

    let packg = {
        schema: schema,
        table: table
    };

    const packgJSON = JSON.stringify(packg);
    // Vanilla JS XHR requires this formatting to send the data
    const data = new URLSearchParams({'content': packgJSON});

    xhr.send(data);

};
<?php

// File with connection info
$config = include('config.php');

// Connection info
$host = $config['host'];
$port = $config['port'];
$database = $config['database'];
$username = $config['username'];
$password = $config['password'];

// POST reception
$packg = json_decode($_POST['content']);
$schema = $packg->schema;
$table = $packg->table;



// File info and paths
$filename = $table;
$rootDir = "tempData/";
$fileDir = $filename . "/";
$filePath = $rootDir . $fileDir;
$completeFilePath = $filePath . $filename;
$shpfile = $filename . ".shp";
$zipped = $filename . ".zip";
$zipFile = $completeFilePath . ".zip";



// Function to send the file (PROBLEM - THIS DOES NOT WORK WITH XHR)
function sendZip($zipFile) {

    $zipName = basename($zipFile);

    header("Content-Type: application/zip");
    header("Content-Disposition: attachment; filename=$zipName");
    header("Content-Length: " . filesize($zipFile));

    ob_flush();
    flush();

    readfile($zipFile);

};


// Send the zip if it's already available (NOT PROBLEMATIC)
if (file_exists($zipFile)) {
    
    sendZip($zipFile);

};


// Get shapefile, zip it and send it, if not available (NOT PROBLEMATIC)
if (!file_exists($zipFile)) {

    // Get files
    exec("mkdir -p -m 777 $filePath");
    exec("pgsql2shp -h $host -p $port -u $username -P $password -g geom -k -f $completeFilePath $database $schema.$table");

    // ZIP the files
    $zip = new ZipArchive;

    if ($zip -> open($zipFile, ZipArchive::CREATE) === TRUE) {

        $handlerDir = opendir($filePath);

        // Iterates all files inside folder
        while ($handlerFile = readdir($handlerDir)) {
            // If the files are indeed files, and not directories
            if (is_file($filePath . $handlerFile) && $handlerFile != "." && $handlerFile != "..") {
                // Zip them
                $zip -> addFile($filePath . $handlerFile, $fileDir . $handlerFile);
            };
        };

        // Close the file
        $zip -> close();

    };

    sendZip($zipFile);

};

?>

标签: javascriptphpdownloadgridjs

解决方案


正如@epascarello here所指出的,一个简单的GET请求就可以解决这个问题。

尽管我害怕POST因为 SQL 注入攻击而无法使用,但变量通过pgsql2shp程序传递,并且只接受有效的模式和表名,因此无需担心。

我目前正在使用这个KISS代码,它可以工作:

const getData = (schema, table) => {
    
    window.location='php/get_data.php?schema=' + schema + '&table=' + table;

};

在 PHP 中,只需要从POST接待到GET接待的微小变化。变量已经分开,不需要解码任何东西:

$schema = $_GET['schema'];
$table = $_GET['table'];

这表明,有时,我们对问题的研究如此深入,以至于解决方案就在我们面前。


推荐阅读