如何使用 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 处理器:
它可以从任何媒体源下载,如果需要,还可以进行访问检查。
回到你的案例,这些例子可能会给你带来一些想法。
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
我正在尝试在 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 处理器:
它可以从任何媒体源下载,如果需要,还可以进行访问检查。
回到你的案例,这些例子可能会给你带来一些想法。
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