Skip to content

Commit

Permalink
Merge pull request #14333 from ian4hu/bugfix/issue-13919
Browse files Browse the repository at this point in the history
Fixes #13919, make response->setFileToSend support non-ASCII filename.
  • Loading branch information
sergeyklay committed Aug 30, 2019
2 parents ab456c1 + 7a9e241 commit 8e4643e
Show file tree
Hide file tree
Showing 4 changed files with 136 additions and 3 deletions.
2 changes: 2 additions & 0 deletions .github/stale.yml
Expand Up @@ -14,6 +14,8 @@ exemptLabels:
- "Bug - High"
- WIP
- Locked
- "Feature - NFR"
- "Enhancement"

# Set to true to ignore issues in a project (defaults to false)
exemptProjects: false
Expand Down
43 changes: 43 additions & 0 deletions phalcon/Helper/Fs.zep
@@ -0,0 +1,43 @@

/**
* This file is part of the Phalcon.
*
* (c) Phalcon Team <team@phalcon.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Phalcon\Helper;

/**
* This class offers file operation helper
*/
class Fs {

/**
* Gets the filename from a given path, Same as PHP's basename() but has non-ASCII support.
* PHP's basename() does not properly support streams or filenames beginning with a non-US-ASCII character.
* see https://bugs.php.net/bug.php?id=37738
*
* @param string $uri
* @param string $suffix
*
* @return string
*/
final public static function basename(string! uri, var suffix = null) -> string
{
var filename, matches;
let uri = rtrim(uri, DIRECTORY_SEPARATOR);
let filename = preg_match(
"@[^" . preg_quote(DIRECTORY_SEPARATOR, "@") . "]+$@",
uri,
matches
) ? matches[0] : "";
if suffix {
let filename = preg_replace("@" . preg_quote(suffix, "@") . "$@", "", filename);
}

return filename;
}
}
21 changes: 18 additions & 3 deletions phalcon/Http/Response.zep
Expand Up @@ -14,6 +14,7 @@ use DateTime;
use DateTimeZone;
use Phalcon\Di;
use Phalcon\Di\DiInterface;
use Phalcon\Helper\Fs;
use Phalcon\Http\Response\Exception;
use Phalcon\Http\Response\HeadersInterface;
use Phalcon\Http\Response\CookiesInterface;
Expand Down Expand Up @@ -546,18 +547,32 @@ class Response implements ResponseInterface, InjectionAwareInterface, EventsAwar
public function setFileToSend(string filePath, attachmentName = null, attachment = true) -> <ResponseInterface>
{
var basePath;
var basePathEncoding = "ASCII";
var basePathEncoded;

if typeof attachmentName != "string" {
let basePath = basename(filePath);
let basePath = Fs::basename(filePath);
} else {
let basePath = attachmentName;
}

if attachment {
let basePathEncoded = rawurlencode(basePath);
// mbstring is a non-default extension
if function_exists("mb_detect_encoding") {
let basePathEncoding = mb_detect_encoding(
basePath,
mb_detect_order(),
true
);
}
this->setRawHeader("Content-Description: File Transfer");
this->setRawHeader("Content-Type: application/octet-stream");
this->setRawHeader("Content-Disposition: attachment; filename=" . basePath . ";");
this->setRawHeader("Content-Transfer-Encoding: binary");
if basePathEncoding != "ASCII" {
this->setRawHeader("Content-Disposition: attachment; filename=" . basePathEncoded . "; filename*=". strtolower(basePathEncoding) . "''" . basePathEncoded);
} else {
this->setRawHeader("Content-Disposition: attachment; filename=" . basePathEncoded);
}
}

let this->file = filePath;
Expand Down
73 changes: 73 additions & 0 deletions tests/unit/Helper/Fs/FsBasenameCest.php
@@ -0,0 +1,73 @@
<?php
declare(strict_types=1);

/**
* This file is part of the Phalcon Framework.
*
* (c) Phalcon Team <team@phalconphp.com>
*
* For the full copyright and license information, please view the LICENSE.txt
* file that was distributed with this source code.
*/

namespace Phalcon\Test\Unit\Helper\Fs;

use Phalcon\Helper\Fs;
use UnitTester;

class FsBasenameCest
{
/**
* Tests Phalcon\Helper\Fs :: basename()
* with ASCII $uri it should be same as PHP's basename
*
* @author Ian Hu <hu2008yinxiang@163.com>
* @since 2019-08-27
*/
public function helperFsBasenamePureASCII(UnitTester $I)
{
$I->wantToTest('Helper\Fs - basename() with pure ASCII uri');
$filePathAndSuffixes = [
["/etc/sudoers.d", ".d"],
["/etc/sudoers.d", ''],
['/etc/passwd', ''],
['/etc/', ''],
['.', ''],
['/', '']
];

foreach ($filePathAndSuffixes as $filePathAndSuffix) {
list($filePath, $suffix) = $filePathAndSuffix;
$I->assertEquals(
basename($filePath, $suffix),
Fs::basename($filePath, $suffix)
);
}
}

/**
* Tests Phalcon\Helper\Fs :: basename()
* with non-ASCII $uri support
*
* @author Ian Hu <hu2008yinxiang@163.com>
* @since 2019-08-27
*/
public function helperFsBasenameNonASCII(UnitTester $I)
{
$I->wantToTest('Helper\Fs - basename() with non-ASCII uri');
$filePathAndExpects = [
'/file/热爱中文.txt' => '热爱中文.txt',
'/中文目录/热爱中文.txt' => '热爱中文.txt',
'/myfolder/日本語のファイル名.txt' => '日本語のファイル名.txt',
'/のファ/日本語のファイル名.txt' => '日本語のファイル名.txt',
'/root/ελληνικά.txt' => 'ελληνικά.txt',
'/νικά/ελληνικά.txt' => 'ελληνικά.txt'
];
foreach ($filePathAndExpects as $filePath => $expect) {
$I->assertEquals(
$expect,
Fs::basename($filePath)
);
}
}
}

0 comments on commit 8e4643e

Please sign in to comment.