update v1.0.4

This commit is contained in:
sujitprasad
2016-01-04 18:05:45 +05:30
parent 372485336b
commit 4864e5a3f1
529 changed files with 20956 additions and 8178 deletions

View File

@@ -1,6 +1,11 @@
CHANGELOG
=========
2.8.0
-----
* added tempnam() a stream aware version of PHP's native tempnam()
2.6.0
-----

View File

@@ -192,12 +192,12 @@ class Filesystem
public function chmod($files, $mode, $umask = 0000, $recursive = false)
{
foreach ($this->toIterator($files) as $file) {
if ($recursive && is_dir($file) && !is_link($file)) {
$this->chmod(new \FilesystemIterator($file), $mode, $umask, true);
}
if (true !== @chmod($file, $mode & ~$umask)) {
throw new IOException(sprintf('Failed to chmod file "%s".', $file), 0, null, $file);
}
if ($recursive && is_dir($file) && !is_link($file)) {
$this->chmod(new \FilesystemIterator($file), $mode, $umask, true);
}
}
}
@@ -443,13 +443,65 @@ class Filesystem
*/
public function isAbsolutePath($file)
{
return (strspn($file, '/\\', 0, 1)
return strspn($file, '/\\', 0, 1)
|| (strlen($file) > 3 && ctype_alpha($file[0])
&& substr($file, 1, 1) === ':'
&& (strspn($file, '/\\', 2, 1))
)
|| null !== parse_url($file, PHP_URL_SCHEME)
);
;
}
/**
* Creates a temporary file with support for custom stream wrappers.
*
* @param string $dir The directory where the temporary filename will be created.
* @param string $prefix The prefix of the generated temporary filename.
* Note: Windows uses only the first three characters of prefix.
*
* @return string The new temporary filename (with path), or throw an exception on failure.
*/
public function tempnam($dir, $prefix)
{
list($scheme, $hierarchy) = $this->getSchemeAndHierarchy($dir);
// If no scheme or scheme is "file" create temp file in local filesystem
if (null === $scheme || 'file' === $scheme) {
$tmpFile = tempnam($hierarchy, $prefix);
// If tempnam failed or no scheme return the filename otherwise prepend the scheme
if (false !== $tmpFile) {
if (null !== $scheme) {
return $scheme.'://'.$tmpFile;
}
return $tmpFile;
}
throw new IOException('A temporary file could not be created.');
}
// Loop until we create a valid temp file or have reached 10 attempts
for ($i = 0; $i < 10; ++$i) {
// Create a unique filename
$tmpFile = $dir.'/'.$prefix.uniqid(mt_rand(), true);
// Use fopen instead of file_exists as some streams do not support stat
// Use mode 'x+' to atomically check existence and create to avoid a TOCTOU vulnerability
$handle = @fopen($tmpFile, 'x+');
// If unsuccessful restart the loop
if (false === $handle) {
continue;
}
// Close the file if it was successfully opened
@fclose($handle);
return $tmpFile;
}
throw new IOException('A temporary file could not be created.');
}
/**
@@ -472,7 +524,7 @@ class Filesystem
throw new IOException(sprintf('Unable to write to the "%s" directory.', $dir), 0, null, $dir);
}
$tmpFile = tempnam($dir, basename($filename));
$tmpFile = $this->tempnam($dir, basename($filename));
if (false === @file_put_contents($tmpFile, $content)) {
throw new IOException(sprintf('Failed to write file "%s".', $filename), 0, null, $filename);
@@ -501,4 +553,18 @@ class Filesystem
return $files;
}
/**
* Gets a 2-tuple of scheme (may be null) and hierarchical part of a filename (e.g. file:///tmp -> array(file, tmp)).
*
* @param string $filename The filename to be parsed.
*
* @return array The filename scheme and hierarchical part
*/
private function getSchemeAndHierarchy($filename)
{
$components = explode('://', $filename, 2);
return 2 === count($components) ? array($components[0], $components[1]) : array(null, $components[0]);
}
}

View File

@@ -483,6 +483,22 @@ class FilesystemTest extends FilesystemTestCase
$this->assertFilePermissions(753, $directory);
}
public function testChmodChangesZeroModeOnSubdirectoriesOnRecursive()
{
$this->markAsSkippedIfChmodIsMissing();
$directory = $this->workspace.DIRECTORY_SEPARATOR.'directory';
$subdirectory = $directory.DIRECTORY_SEPARATOR.'subdirectory';
mkdir($directory);
mkdir($subdirectory);
chmod($subdirectory, 0000);
$this->filesystem->chmod($directory, 0753, 0000, true);
$this->assertFilePermissions(753, $subdirectory);
}
public function testChown()
{
$this->markAsSkippedIfPosixIsMissing();
@@ -946,6 +962,110 @@ class FilesystemTest extends FilesystemTestCase
);
}
public function testTempnam()
{
$dirname = $this->workspace;
$filename = $this->filesystem->tempnam($dirname, 'foo');
$this->assertFileExists($filename);
}
public function testTempnamWithFileScheme()
{
$scheme = 'file://';
$dirname = $scheme.$this->workspace;
$filename = $this->filesystem->tempnam($dirname, 'foo');
$this->assertStringStartsWith($scheme, $filename);
$this->assertFileExists($filename);
}
public function testTempnamWithMockScheme()
{
stream_wrapper_register('mock', 'Symfony\Component\Filesystem\Tests\Fixtures\MockStream\MockStream');
$scheme = 'mock://';
$dirname = $scheme.$this->workspace;
$filename = $this->filesystem->tempnam($dirname, 'foo');
$this->assertStringStartsWith($scheme, $filename);
$this->assertFileExists($filename);
}
/**
* @expectedException \Symfony\Component\Filesystem\Exception\IOException
*/
public function testTempnamWithZlibSchemeFails()
{
$scheme = 'compress.zlib://';
$dirname = $scheme.$this->workspace;
// The compress.zlib:// stream does not support mode x: creates the file, errors "failed to open stream: operation failed" and returns false
$this->filesystem->tempnam($dirname, 'bar');
}
public function testTempnamWithPHPTempSchemeFails()
{
$scheme = 'php://temp';
$dirname = $scheme;
$filename = $this->filesystem->tempnam($dirname, 'bar');
$this->assertStringStartsWith($scheme, $filename);
// The php://temp stream deletes the file after close
$this->assertFileNotExists($filename);
}
/**
* @expectedException \Symfony\Component\Filesystem\Exception\IOException
*/
public function testTempnamWithPharSchemeFails()
{
// Skip test if Phar disabled phar.readonly must be 0 in php.ini
if (!\Phar::canWrite()) {
$this->markTestSkipped('This test cannot run when phar.readonly is 1.');
}
$scheme = 'phar://';
$dirname = $scheme.$this->workspace;
$pharname = 'foo.phar';
new \Phar($this->workspace.'/'.$pharname, 0, $pharname);
// The phar:// stream does not support mode x: fails to create file, errors "failed to open stream: phar error: "$filename" is not a file in phar "$pharname"" and returns false
$this->filesystem->tempnam($dirname, $pharname.'/bar');
}
/**
* @expectedException \Symfony\Component\Filesystem\Exception\IOException
*/
public function testTempnamWithHTTPSchemeFails()
{
$scheme = 'http://';
$dirname = $scheme.$this->workspace;
// The http:// scheme is read-only
$this->filesystem->tempnam($dirname, 'bar');
}
public function testTempnamOnUnwritableFallsBackToSysTmp()
{
$scheme = 'file://';
$dirname = $scheme.$this->workspace.DIRECTORY_SEPARATOR.'does_not_exist';
$filename = $this->filesystem->tempnam($dirname, 'bar');
$realTempDir = realpath(sys_get_temp_dir());
$this->assertStringStartsWith(rtrim($scheme.$realTempDir, DIRECTORY_SEPARATOR), $filename);
$this->assertFileExists($filename);
// Tear down
@unlink($filename);
}
public function testDumpFile()
{
$filename = $this->workspace.DIRECTORY_SEPARATOR.'foo'.DIRECTORY_SEPARATOR.'baz.txt';
@@ -1000,6 +1120,33 @@ class FilesystemTest extends FilesystemTestCase
$this->assertSame('bar', file_get_contents($filename));
}
public function testDumpFileWithFileScheme()
{
if (defined('HHVM_VERSION')) {
$this->markTestSkipped('HHVM does not handle the file:// scheme correctly');
}
$scheme = 'file://';
$filename = $scheme.$this->workspace.DIRECTORY_SEPARATOR.'foo'.DIRECTORY_SEPARATOR.'baz.txt';
$this->filesystem->dumpFile($filename, 'bar', null);
$this->assertFileExists($filename);
$this->assertSame('bar', file_get_contents($filename));
}
public function testDumpFileWithZlibScheme()
{
$scheme = 'compress.zlib://';
$filename = $this->workspace.DIRECTORY_SEPARATOR.'foo'.DIRECTORY_SEPARATOR.'baz.txt';
$this->filesystem->dumpFile($filename, 'bar', null);
// Zlib stat uses file:// wrapper so remove scheme
$this->assertFileExists(str_replace($scheme, '', $filename));
$this->assertSame('bar', file_get_contents($filename));
}
public function testCopyShouldKeepExecutionPermission()
{
$this->markAsSkippedIfChmodIsMissing();

View File

@@ -0,0 +1,46 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Filesystem\Tests\Fixtures\MockStream;
/**
* Mock stream class to be used with stream_wrapper_register.
* stream_wrapper_register('mock', 'Symfony\Component\Filesystem\Tests\Fixtures\MockStream\MockStream').
*/
class MockStream
{
/**
* Opens file or URL.
*
* @param string $path Specifies the URL that was passed to the original function
* @param string $mode The mode used to open the file, as detailed for fopen()
* @param int $options Holds additional flags set by the streams API
* @param string $opened_path If the path is opened successfully, and STREAM_USE_PATH is set in options,
* opened_path should be set to the full path of the file/resource that was actually opened
*
* @return bool
*/
public function stream_open($path, $mode, $options, &$opened_path)
{
return true;
}
/**
* @param string $path The file path or URL to stat
* @param array $flags Holds additional flags set by the streams API
*
* @return array File stats
*/
public function url_stat($path, $flags)
{
return array();
}
}

View File

@@ -19,12 +19,15 @@
"php": ">=5.3.9"
},
"autoload": {
"psr-4": { "Symfony\\Component\\Filesystem\\": "" }
"psr-4": { "Symfony\\Component\\Filesystem\\": "" },
"exclude-from-classmap": [
"/Tests/"
]
},
"minimum-stability": "dev",
"extra": {
"branch-alias": {
"dev-master": "2.7-dev"
"dev-master": "2.8-dev"
}
}
}

View File

@@ -21,6 +21,7 @@
<directory>./</directory>
<exclude>
<directory>./Tests</directory>
<directory>./vendor</directory>
</exclude>
</whitelist>
</filter>