diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 0000000..8d7af73 --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,39 @@ +build: false +platform: + - x86 + - x64 + +clone_folder: c:\projects\php-http\multipart-stream-builder + +cache: + - c:\tools\php -> appveyor.yml + +init: + - SET PATH=c:\php;%PATH% + - SET COMPOSER_NO_INTERACTION=1 + - SET PHP=1 + + +install: + - IF EXIST c:\php (SET PHP=0) ELSE (mkdir c:\php) + - cd c:\php + - IF %PHP%==1 appveyor DownloadFile http://windows.php.net/downloads/releases/archives/php-7.0.0-nts-Win32-VC14-x86.zip + - IF %PHP%==1 7z x php-7.0.0-nts-Win32-VC14-x86.zip -y >nul + - IF %PHP%==1 del /Q *.zip + - IF %PHP%==1 echo @php %%~dp0composer.phar %%* > composer.bat + - IF %PHP%==1 copy /Y php.ini-development php.ini + - IF %PHP%==1 echo max_execution_time=1200 >> php.ini + - IF %PHP%==1 echo date.timezone="UTC" >> php.ini + - IF %PHP%==1 echo extension_dir=ext >> php.ini + - IF %PHP%==1 echo extension=php_openssl.dll >> php.ini + - IF %PHP%==1 echo extension=php_mbstring.dll >> php.ini + - IF %PHP%==1 echo extension=php_fileinfo.dll >> php.ini + - appveyor DownloadFile https://getcomposer.org/composer.phar + - cd c:\projects\php-http\multipart-stream-builder + - mkdir %APPDATA%\Composer + - composer update --prefer-dist --no-progress --ansi + +test_script: + - cd c:\projects\php-http\multipart-stream-builder + - vendor\bin\phpunit.bat --verbose + diff --git a/src/MultipartStreamBuilder.php b/src/MultipartStreamBuilder.php index cd59b44..5a62d75 100644 --- a/src/MultipartStreamBuilder.php +++ b/src/MultipartStreamBuilder.php @@ -121,7 +121,7 @@ private function prepareHeaders($name, StreamInterface $stream, $filename, array if (!$this->hasHeader($headers, 'content-disposition')) { $headers['Content-Disposition'] = sprintf('form-data; name="%s"', $name); if ($hasFilename) { - $headers['Content-Disposition'] .= sprintf('; filename="%s"', pathinfo($filename, PATHINFO_BASENAME)); + $headers['Content-Disposition'] .= sprintf('; filename="%s"', $this->basename($filename)); } } @@ -228,4 +228,31 @@ public function setMimetypeHelper(MimetypeHelper $mimetypeHelper) return $this; } + + /** + * Gets the filename from a given path. + * + * PHP's basename() does not properly support streams or filenames beginning with a non-US-ASCII character. + * + * @author Drupal 8.2 + * + * @param string $path + * + * @return string + */ + private function basename($path) + { + $separators = '/'; + if (DIRECTORY_SEPARATOR != '/') { + // For Windows OS add special separator. + $separators .= DIRECTORY_SEPARATOR; + } + // Remove right-most slashes when $uri points to directory. + $path = rtrim($path, $separators); + // Returns the trailing part of the $uri starting after one of the directory + // separators. + $filename = preg_match('@[^'.preg_quote($separators, '@').']+$@', $path, $matches) ? $matches[0] : ''; + + return $filename; + } } diff --git a/tests/FunctionTest.php b/tests/FunctionTest.php index e29f97d..3323bf2 100644 --- a/tests/FunctionTest.php +++ b/tests/FunctionTest.php @@ -33,6 +33,26 @@ public function testSupportResources() $this->assertTrue(false !== strpos($multipartStream, 'Content-Type: image/png')); } + public function testResourceFilenameIsNotLocaleAware() + { + // Get current locale + $originalLocale = setlocale(LC_ALL, "0"); + + // Set locale to something strange. + setlocale(LC_ALL, 'C'); + + $resource = fopen(__DIR__.'/Resources/httplug.png', 'r'); + $builder = new MultipartStreamBuilder(); + $builder->addResource('image', $resource, ['filename'=> 'äa.png']); + + $multipartStream = (string) $builder->build(); + $this->assertTrue(0 < preg_match('|filename="([^"]*?)"|si', $multipartStream, $matches), 'Could not find any filename in output.'); + $this->assertEquals('äa.png', $matches[1]); + + // Reset the locale + setlocale(LC_ALL, $originalLocale); + } + public function testHeaders() { $builder = new MultipartStreamBuilder();