如何使用 ajax 执行 php 将文件推送到浏览器的功能?

How to use ajax to execute php function that will push a file to the browser?

我正在尝试在 php class 中编写一个方法,该方法将使用 ajax 来执行 php 函数,该函数会将文件推回浏览器。

似乎正在尝试将文件写入 modx 日志,其中出现大量二进制垃圾。

方法如下:

public function pushDocuments($formdata){

    $data = $formdata['formdata'];

    $file = MODX_PROTECTED_STORAGE . $data['target'];

    $file_name = basename($file);

    if (file_exists($file)) {

        header("Content-Disposition: attachment; filename=\"$file_name\"");
        header("Content-Length: " . filesize($file));
        header("Content-Type: application/octet-stream;");
        readfile($file);

    };

    $output = array(

        'status' => 'success',
        'error_messages' => array(),
        'success_messages' => array(),

    );

    $output = $this->modx->toJSON($output);

    return $output;

}

这里是 jquery:

$('.btn-get-document').click(function(){

    var target = $(this).attr('data-target');
    var postdata = {"snippet":"DataSync", "function":"pushDocuments", "target": target}; // data object ~ not json!!
    console.log('target = ' + target + postdata );

    $.ajax({
        type: "POST",
        url: "processors/processor.ajax.generic/",
        dataType  : "json",
        cache : false,
        data: postdata, // posting object, not json
        success: function(data){
            if(data.status == 'success'){
                console.log("SUCCESS status posting data");
            }else if(data.status == 'error'){
                console.log("error status posting data");
            }

        },
        error: function(data){
                console.log("FATAL: error posting data");
            }
    });
});

它 运行 通过脚本并在控制台中成功 [因为我强制成功] 但是没有文件提示下载并且二进制垃圾显示在 modx 日志中

我做错了什么?

要下载文件,您必须使用 JS 重定向到文件的位置。您不能通过 AJAX 提取文件内容并指示浏览器将这些内容保存为文件。

您需要在结构上更改您的设置。例如,你的 PHP 脚本可以验证要下载的文件是否存在,然后发送 link 给 JS 以下载文件。像这样:

if ( file_exists( $file )) {
    $success_message = array(
        'file_url' => 'http://example.com/file/to/download.zip'
   );
}

$output = array(
    'status'           => 'success',
    'error_messages'   => array(),
    'success_messages' => $success_message
);

然后像这样修改 AJAX return 的 "success" 部分:

success: function( data ) {
    if ( data.status == 'success' ) {
        location.href = data.success_messages.file_url;
    } else if ( data.status == 'error' ) {
        console.log( 'error status posting data' );
    }
},

由于您指向一个文件,浏览器 window 实际上不会去任何地方,只要文件的 content-disposition 设置为附件。如果您定向到浏览器未在内部处理的任何文件(如 ZIP 文件),通常会发生这种情况。如果你想控制它以便它下载所有文件(包括浏览器可能使用插件处理的东西),你可以指向另一个 PHP 脚本,该脚本将发送适当的 headers 然后发送文件(类似于您发送 headers 并在示例中使用 readfile() 的方式。

@sean-kimball,

您可能想要扩展 MODX 的 class 处理器:

https://github.com/modxcms/revolution/blob/master/core/model/modx/processors/browser/file/download.class.php

它可以从任何媒体源下载,如果需要,还可以进行访问检查。

它在管理端的实现是: https://github.com/modxcms/revolution/blob/master/manager/assets/modext/widgets/system/modx.tree.directory.js#L553

回到你的案例,这些例子可能会给你带来一些想法。

JS 示例:

$.ajax({
    type: "POST",
    // read my note down below about connector file
    url: "assets/components/mypackage/connectors/web.php", 
    dataType  : "json",
    cache : false,
    data: {
        action: 'mypath/to/processor/classfile'
    }
    success: function(data){

    },
    error: function(data){
        console.log("FATAL: error posting data");
    }
});

处理器示例:

<?php

require_once MODX_CORE_PATH . 'model/modx/processors/browser/file/download.class.php';

class myDownloadProcessor extends modBrowserFileDownloadProcessor {
    // override things in here
}

return 'myDownloadProcessor';

为此,我还建议您使用 MODX 的 index.php 主文件作为 AJAX 的连接器,以便处理器中的 $modx 对象也继承访问权限。

http://www.virtudraft.com/blog/ajaxs-connector-file-using-modxs-main-index.php.html