php编码 - 如果我的文件使用希腊字符保存,则无法下载

时间:2012-04-27 07:13:05

标签: php encoding

我正在创建一些下载链接。我的问题是,如果使用英文字符保存“MY_FILE_NAME.doc”文件,则下载。如果我使用希腊字符保存它,那么我无法下载...我正在使用utf-8编码。

(我不知道这是否重要,但我在我的页面上显示希腊字符而没有任何问题)

这是我的链接:

<!DOCTYPE>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>CFS Portal</title>
</head>
<body>
<div>
<span class="txt">
<a href="scripts/download.php?file=MY_FILE_NAME.doc" class="dload">Ιατρικό</a>
</span></div>
</body>

和我的download.php文件:

<?php
// block any attempt to the filesystem
if (isset($_GET['file']) && basename($_GET['file']) == $_GET['file']) {
    $filename = $_GET['file'];
} else {
    $filename = NULL;
}

$err = '<p class="err_msg">
STOP / ΣΤΑΜΑΤΗΣΤΕ
</p>';

if (!$filename) {
        // if variable $filename is NULL or false display the message
        echo $err;
    } else {
        // define the path to your download folder plus assign the file name
        $path = 'downloads/'.$filename;
        // check that file exists and is readable
        if (file_exists($path) && is_readable($path)) {
            // get the file size and send the http headers
            $size = filesize($path);
            header('Content-Type: application/octet-stream;');
            header('Content-Length: '.$size);
            header('Content-Disposition: attachment; filename='.$filename);
            header('Content-Transfer-Encoding: binary');
            // open the file in binary read-only mode
            // display the error messages if the file can´t be opened
            $file = @ fopen($path, 'rb');
            if ($file) {
                // stream the file and exit the script when complete
                fpassthru($file);
                exit;
            } else {
                echo $err;
            }
        } else {
            echo $err;
        }
    }
?>

2 个答案:

答案 0 :(得分:2)

您的脚本可能有几个问题:

1。文件系统编码问题

要实际访问文件系统上的文件,必须正确编码文件名。 LC_CTYPE语言环境参数告知哪个是磁盘上文件名的预期编码。

在Unix / Linux或类似操作系统下,该参数可能会评估为&#34; en_US.UTF-8&#34;这意味着文件名的编码是UTF-8,因此您的脚本不需要转换。

在Windows服务器下不允许使用UTF-8,通常LC_CTYPE评估为&#34; language_country.codepage&#34;其中&#34;代码页&#34;是当前活动代码页的编号,例如1252(西方国家)或1253(希腊语)。这里http://www.unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/是Windows下可用代码页的列表。然后,在Windows下,您需要将UTF-8文件名转换为其他名称才能从磁盘读取它。更多细节可以在我对PHP bug no的回复中找到。 47096可从https://bugs.php.net/bug.php?id=47096

获取

2。 HTTP文件名编码问题

根据我的经验,不同的浏览器支持不同的方式来编码非ASCII文件名,并且当存在特殊或无效字符时表现不同(例如,在Windows下,问号&#39;?&#39;不是允许在文件名中,浏览器只需删除该char或完全替换整个文件名与另一个随机生成的文件名。无论如何,以下大部分代码都适用于大多数浏览器:


    $file_name = "Caffé Brillì.pdf";   # file name, UTF-8 encoded
    $file_mime = "application/pdf";    # MIME type
    $file_path = "absolute/or/relative/path/file";

    header("Content-Type: $file_mime");
    header("Content-Length: " . filesize($file_path));
    $agent = $_SERVER["HTTP_USER_AGENT"];
    if( is_int(strpos($agent, "MSIE")) ){
        # Remove reserved chars: :\/*?"|
        $fn = preg_replace('/[:\\x5c\\/*?"|]/', '_', $file_name);
        # Non-standard URL encoding:
        header("Content-Disposition: attachment; filename="
        . rawurlencode($fn));

    } else if( is_int(strpos($agent, "Gecko")) ){
        # RFC 2231:
        header("Content-Disposition: attachment; filename*=UTF-8''"
        . rawurlencode($file_name));

    } else if( is_int(strpos($agent, "Opera")) ) {
        # Remove reserved chars: :\/*{?
        $fn = preg_replace('/[:\\x5c\\/{?]/', '_', $file_name);
        # RFC 2231:
        header("Content-Disposition: attachment; filename*=UTF-8''"
        . rawurlencode($fn));

    } else {
        # RFC 2616 ASCII-only encoding:
        $fn = mb_convert_encoding($file_name, "US-ASCII", "UTF-8");
        $fn = (string) str_replace("\\", "\\\\", $fn);
        $fn = (string) str_replace("\"", "\\\"", $fn);
        header("Content-Disposition: attachment; filename=\"$fn\"");
    }

    readfile($file_path);

希望这可能会有所帮助。

答案 1 :(得分:0)

我认为问题在于[在脚本和文件系统之间]的编码。

验证您在底层文件系统上使用的编码,因为这是您访问文件的方式(即文件系统是使用iso-8859-1 [或类似],并且您将变量发送为UTF-8 - 然后有一个问题。

或者它可能就像你应该从get获取的var上做一个urldecode一样简单(你可能还需要在此之后进一步对其进行编码以达到文件系统的编码)。

$filename = urldecode($_GET['file']);