PHP - Windows - 上传后文件名不正确(ü保存为Ã等)

时间:2015-01-15 01:49:37

标签: php windows encoding filenames

我有这个自制的应用程序允许多个文件上传,我用AJAX传递文件到PHP,用PHP创建新的目录,移动上传文件并将目录位置保存到数据库。然后查看我运行的文件列出了db。中保存的目录位置。

问题是文件来自世界各地,因此他们经常会有一些非拉丁字符,例如ü。当我回复php名称中的文件名时,即使他们的名字用阿拉伯语写成,它们也会被保存在服务器上,编码名称例如Ã代替ü。当我列出目录中的文件时,我可以看到ü.txt的名称是Ã.txt但是当我点击它时服务器返回错误对象未找到(因为在服务器上它保存为Ã.txt并且它读取链接为ü.txt)。

我尝试了一些建议的解决方案,例如使用iconv,但文件名仍然以相同的方式保存。

我可以发誓当网络应用程序在Linux上托管时问题不存在,但此刻我不再那么肯定了。现在我暂时在xampp上运行它(在Windows上),似乎文件名是使用windows-1252编码保存的(服务器上的默认Windows编码)。它是默认的Windows编码相关问题吗?

说实话,我不知道如何处理这个问题,我将不胜感激任何帮助。我应该继续尝试以不同的字符编码保存文件,还是以不同的方式处理它并改变列出已保存和编码的文件的方式更好?

EDIT。根据(最终)关闭bug report,它已在php 7.1中修复。

2 个答案:

答案 0 :(得分:1)

最后,我采用以下方法解决了这个问题:

  1. 上传文件时,我会使用rawurlencode()
  2. 对您的名称进行编码
  3. 从服务器获取文件时,它们显然是URL编码的,因此我使用urldecode($filename)来打印正确的名称
  4. a href中的链接会自动翻译,因此例如“%20”变为“”,并且URL最终会变得不正确,因为它链接到错误的文件名。我决定对它们进行编码并打印出最终结果如下:print $dirReceived.rawurlencode($file);($ dirReceived是存储接收文件的目录,在代码中先前定义)
  5. 我还在urldecode($filename)添加了下载属性,以便在需要时使用UTF-8名称保存文件。
  6. 由于这个原因,我在服务器上保存了带有url编码名称的文件。可以在浏览器中打开它们(非常重要,因为它们大多数是* .pdf)并且可以使用正确的名称下载它们,这样我就可以上传和下载名称用阿拉伯语,西里尔语等编写的文件。

    到目前为止,我测试了它并且看起来不错。我正在考虑在生产代码中实现它。对它的任何担忧/想法?

    EDIT。

    由于没有异议,我选择我的答案作为解决我问题的答案。做了一些测试后,客户端和服务器端的一切看起来都不错。在服务器上保存文件时,它们是URL编码的,下载时它们会被解码并以正确的名称保存。

    一开始我使用的是代码:

        for($i=0;$i<count($_FILES['file']['name']);$i++) 
    {
        move_uploaded_file($_FILES['file']['tmp_name'][$i],
        "../filepath/" . $_FILES['file']['name'][$i]);
    }
    

    此方法在保存文件时导致问题,并用cp1252编码的一个替换每个UTF-8特殊字符(ü保存为Ã等),所以我添加了一行并用以下代码替换了该代码:

    for($i=0;$i<count($_FILES['file']['name']);$i++) 
    {
        $fname= rawurlencode($_FILES['file']['name'][$i]);
        move_uploaded_file($_FILES['file']['tmp_name'][$i],
        "../filepath/" . $fname);
    }
    

    这允许我使用与cp1252和UTF-8兼容的URL编码(%和两个十六进制)在服务器上保存任何文件名。

    要列出保存的文件,我使用已保存在数据库中的文件路径并列出文件。我使用以下代码:

        if (is_dir($dir)){
      if ($dh = opendir($dir)){
        while (($file = readdir($dh)) !== false){
            if(is_file($dir . $file)){
    
        echo "<li><a href='".$dir.$file."' download='".$file ."'>".$file."</a></li><br />";
    
        }
    }
        closedir($dh);
      }
    }
    

    由于URL编码的文件名已自动解码,我将其更改为:

        if (is_dir($dir)){
      if ($dh = opendir($dir)){
        while (($file = readdir($dh)) !== false){
            if(is_file($dir . $file)){
                echo "<li><a href='";
                print $dir.rawurlencode($file);
                echo "' download='" . urldecode($file) ."'>".urldecode($file)."</a></li><br />";
        }
    }
        closedir($dh);
      }
    }
    

    我不知道这是解决问题的最佳方法,但效果很好,我也知道通常不使用php生成html标签是一种好习惯,但此刻我有一些关键错误首先需要解决,然后我将不得不处理代码本身的外观。

    EDIT2

    同样最棒的是我不必更改已经上传的文件的名称,在我看来这是一个很大的优势。

答案 1 :(得分:0)

您使用$_FILES['upfile']['name']命名文件吗?这可能会造成你的问题。

如何使用GNU Recode?

$fileName = recode_string('latin1',$_FILES['upfile']['name']);

语法:

recode_string(string recode type,string $string)

有效字符集:http://www.faqs.org/rfcs/rfc1345.html

不知何故,您必须验证上传文件名中的字符。

你也可以试试sprintf。格式化的字符串字符可能是不可预测的,但可能会起作用。

$fileName = pathinfo($_FILES['upfile']['name'], PATHINFO_FILENAME);
$fileName = sprintf('./uploads/%s',$fileName);

保存文件名时,请使用mysql_escape_string();

$fileName = mysql_escape_string($fileName);

对于语法语法纳粹,我很乐意告诉我,我已经贬值,好像我还不知道。

mysqli_real_escape_string()

请注意,mysqli Grammar Nazis 喜欢对我的答案进行投票,因为我使用mysql而不是msqli,获得生命。我一直在编写代码,因为它是在带有纸张类型和打卡的电传打字机上完成的。早在你出生之前。