跨域上传

发布于 2024-12-05 19:59:36 字数 71 浏览 0 评论 0原文

有没有办法使用 url A 中的表单上传文件,该表单在其“action”属性中指向 url B,而不将页面重定向到 url B?

Are there ways to upload files using a form in url A that points to url B in its "action" attribute without redirecting the page to url B?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

∝单色的世界 2024-12-12 19:59:36

我知道已经是三年后的事了,但由于我今天也有同样的问题,所以我想我应该在这里发布我的解决方案。它不是最漂亮的,但它使用 iframe,这应该有助于它得到旧版浏览器的更多支持。 iframe 的最大挑战是,出于安全原因,如果 iframe 位于另一个域中,您将无法读取 iframe 的内容(浏览器限制所述功能)。

本质上,我的解决方案是这样的:

  1. 用户选择要上传的文件。
  2. 包含文件字段的表单发送针对隐藏 iframe 的 POST 请求。
  3. PHP 脚本在处​​理程序脚本中执行,上传文件。
  4. 当脚本完成(或出错)时,它会发送 Location 重定向,将 iframe 发送回 HTTP_REFERER,这将与表单页面位于同一域中,这意味着脚本将能够读取内容。
  5. 为了沿着重定向发送有用的信息,我只需添加到引用页面的 GET 参数即可。这些可以通过 JavaScript 提取和读取。

HTML:

<form method="post" action="http://other/website/upload.php" enctype="multipart/form-data">
    <input type="file" name="file" />
</form>
<br /><br />
<img id="avatar" />

JavaScript:

$('form').submit(function () {
    $('<iframe></iframe>').attr({name: 'iframe', id: 'iframe'}).prependTo($('body')).load(function () {
        var response = JSON.parse(decodeURIComponent(/[\\?&]_response=([^&#]*)/.exec(this.contentWindow.location.href)[1]).replace(/\+/g, ' '));
        if (response.error) {
            alert(response.error);
        } else {
            $('#avatar').attr('src', response.url);
        }

        $(this).remove();
    });
    $(this).attr('target', 'iframe');
});

$('input[name="avatar"]').change(function () {
    $('form').submit();
});

PHP:

<?php
define('MAX_SIZE', 28 * 1024); // 28 KB
define('UPLOAD_PATH', 'uploads/');
define('UPLOAD_URI', 'http://other/website/uploads/');

header('Content-Type: application/json');
header('Access-Control-Allow-Origin: *');

function format_size ($bytes) {
    for ($labels = array ('B', 'KB', 'MB', 'GB', 'TB'), $x = 0; $bytes >= 1024 && $x < count($labels)-1; $bytes /= 1024, ++$x);
    return round($bytes, 2) . ' ' . $labels[$x];
}

function respond ($message) {
    parse_str(parse_url($_SERVER['HTTP_REFERER'], PHP_URL_QUERY), $params);
    $params = array_merge($params, array ('_response' => json_encode($message)));
    header('Location: ' . $_SERVER['HTTP_REFERER'] . '?' . http_build_query($params));
    exit;
}

if (isset($_FILES['file'])) {
    $file = $_FILES['file'];
    switch ($file['error']) {
        case UPLOAD_ERR_INI_SIZE:
        case UPLOAD_ERR_FORM_SIZE:
            respond(array ('error' => 'You may not upload a file larger than ' . format_size(MAX_SIZE) . '.'));
            break;
        case UPLOAD_ERR_PARTIAL:
        case UPLOAD_ERR_NO_TMP_DIR:
        case UPLOAD_ERR_CANT_WRITE:
        case UPLOAD_ERR_EXTENSION:
            respond(array ('error' => 'The server could not upload the file.'));
            break;
    }

    if ($file['size'] > MAX_SIZE) {
        respond(array ('error' => 'You may not upload a file larger than ' . format_size(MAX_SIZE) . '.'));
    } else if (!in_array($file['type'], array ('image/png', 'image/gif', 'image/jpeg'))) {
        respond(array ('error' => 'The uploaded file must be a PNG, GIF, or JPEG image.'));
    }

    $split = explode('.', basename($file['name']));
    $ext = array_pop($split);
    $name = implode('.', array_merge($split, array (uniqid(), $ext)));
    if (!move_uploaded_file($file['tmp_name'], UPLOAD_PATH . $name)) {
        respond(array ('error' => 'The server could not upload the file.'));
    } else {
        respond(array ('url' => UPLOAD_URI . $name));
    }
}
?>

I know it's 3 years later, but since I had this same question myself today, I figured I'd post my solution here. It's not the prettiest, but it uses an iframe, which should help it be more supported by legacy browsers. The biggest challenge of the iframe is that you can't read the contents of an iframe if it's on another domain for security reasons (the browser restricts said functionality).

In essence, my solution is this:

  1. The user selects a file to upload.
  2. The form that encases the file field sends a POST request targeting a hidden iframe.
  3. A PHP script executes in the handler script, uploading the file.
  4. When the script is done (or errored out), it sends a Location redirect, sending the iframe back to HTTP_REFERER, which will be the on the same domain as the form page, which means that the script will be able to read the contents.
  5. In order to send useful information along the redirect, I simply add onto the GET parameters of the referrer page. These can be extracted and read via JavaScript.

The HTML:

<form method="post" action="http://other/website/upload.php" enctype="multipart/form-data">
    <input type="file" name="file" />
</form>
<br /><br />
<img id="avatar" />

The JavaScript:

$('form').submit(function () {
    $('<iframe></iframe>').attr({name: 'iframe', id: 'iframe'}).prependTo($('body')).load(function () {
        var response = JSON.parse(decodeURIComponent(/[\\?&]_response=([^&#]*)/.exec(this.contentWindow.location.href)[1]).replace(/\+/g, ' '));
        if (response.error) {
            alert(response.error);
        } else {
            $('#avatar').attr('src', response.url);
        }

        $(this).remove();
    });
    $(this).attr('target', 'iframe');
});

$('input[name="avatar"]').change(function () {
    $('form').submit();
});

The PHP:

<?php
define('MAX_SIZE', 28 * 1024); // 28 KB
define('UPLOAD_PATH', 'uploads/');
define('UPLOAD_URI', 'http://other/website/uploads/');

header('Content-Type: application/json');
header('Access-Control-Allow-Origin: *');

function format_size ($bytes) {
    for ($labels = array ('B', 'KB', 'MB', 'GB', 'TB'), $x = 0; $bytes >= 1024 && $x < count($labels)-1; $bytes /= 1024, ++$x);
    return round($bytes, 2) . ' ' . $labels[$x];
}

function respond ($message) {
    parse_str(parse_url($_SERVER['HTTP_REFERER'], PHP_URL_QUERY), $params);
    $params = array_merge($params, array ('_response' => json_encode($message)));
    header('Location: ' . $_SERVER['HTTP_REFERER'] . '?' . http_build_query($params));
    exit;
}

if (isset($_FILES['file'])) {
    $file = $_FILES['file'];
    switch ($file['error']) {
        case UPLOAD_ERR_INI_SIZE:
        case UPLOAD_ERR_FORM_SIZE:
            respond(array ('error' => 'You may not upload a file larger than ' . format_size(MAX_SIZE) . '.'));
            break;
        case UPLOAD_ERR_PARTIAL:
        case UPLOAD_ERR_NO_TMP_DIR:
        case UPLOAD_ERR_CANT_WRITE:
        case UPLOAD_ERR_EXTENSION:
            respond(array ('error' => 'The server could not upload the file.'));
            break;
    }

    if ($file['size'] > MAX_SIZE) {
        respond(array ('error' => 'You may not upload a file larger than ' . format_size(MAX_SIZE) . '.'));
    } else if (!in_array($file['type'], array ('image/png', 'image/gif', 'image/jpeg'))) {
        respond(array ('error' => 'The uploaded file must be a PNG, GIF, or JPEG image.'));
    }

    $split = explode('.', basename($file['name']));
    $ext = array_pop($split);
    $name = implode('.', array_merge($split, array (uniqid(), $ext)));
    if (!move_uploaded_file($file['tmp_name'], UPLOAD_PATH . $name)) {
        respond(array ('error' => 'The server could not upload the file.'));
    } else {
        respond(array ('url' => UPLOAD_URI . $name));
    }
}
?>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文