Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

[2.7][Filesystem] Changed dumpFile to allow dumping to streams... #14754

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
[Filesystem] added tempnam() stream wrapper aware version of PHP's na…
…tive tempnam() and fixed dumpFile to allow dumping to streams
  • Loading branch information
markchalloner committed Jun 3, 2015
commit 86fed591ae3c2ed4432c4fe06dc9dda6da4af36f
5 changes: 5 additions & 0 deletions 5 src/Symfony/Component/Filesystem/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
CHANGELOG
=========

2.7.0
-----

* added tempnam() a stream aware version of PHP's native tempnam()

2.6.0
-----

Expand Down
68 changes: 67 additions & 1 deletion 68 src/Symfony/Component/Filesystem/Filesystem.php
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,57 @@ public function isAbsolutePath($file)
);
}

/**
* 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 false on failure.
*/
public function tempnam($dir, $prefix)
{
$limit = 10;
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
return false === $tmpFile || null === $scheme ? $tmpFile : $scheme.'://'.$tmpFile;
}

// Loop until we create a valid temp file or have reached $limit attempts
for ($i = 0; $i < $limit; $i++) {

// Create a unique filename
$tmpFile = $dir.'/'.$prefix.uniqid(mt_rand(), true);

// If the file already exists restart the loop
// Use fopen instead of file_exists as some streams do not support stat
$handle = @fopen($tmpFile, 'r');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why don't you use file_exists (or is_readable)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@staabm. See comment just above :)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

arghs sry ;)

if (false !== $handle) {
continue;
}

// Close the file if it was successfully opened
@fclose($handle);

// Create the file, if unsuccessful then stream is not writable so set to false
// Use file_put_contents instead of touch as it supports stream wrappers
if (false === @file_put_contents($tmpFile, '')) {
return false;
}

return $tmpFile;

}

return false;
}

/**
* Atomically dumps content into a file.
*
Expand All @@ -468,7 +519,7 @@ public function dumpFile($filename, $content, $mode = 0666)
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);
Expand Down Expand Up @@ -497,4 +548,19 @@ private function toIterator($files)

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 count($components) >= 2 ? array($components[0], $components[1]) : array(null, $components[0]);
}

}
4 changes: 4 additions & 0 deletions 4 src/Symfony/Component/Filesystem/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,15 @@ $filesystem->rename($origin, $target);

$filesystem->symlink($originDir, $targetDir, $copyOnWindows = false);

$filesystem->tempnam($dir, $prefix);

$filesystem->makePathRelative($endPath, $startPath);

$filesystem->mirror($originDir, $targetDir, \Traversable $iterator = null, $options = array());

$filesystem->isAbsolutePath($file);

$filesystem->dumpFile($file, $content);
```

Resources
Expand Down
83 changes: 83 additions & 0 deletions 83 src/Symfony/Component/Filesystem/Tests/FilesystemTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -955,6 +955,66 @@ public function providePathsForIsAbsolutePath()
);
}

public function testTempnam()
{
$dirname = $this->workspace;

$filename = $this->filesystem->tempnam($dirname, 'foo');

$this->assertNotFalse($filename);
$this->assertFileExists($filename);
}

public function testTempnamWithFileScheme()
{
$scheme = 'file://';
$dirname = $scheme.$this->workspace;

$filename = $this->filesystem->tempnam($dirname, 'foo');

$this->assertNotFalse($filename);
$this->assertStringStartsWith($scheme, $filename);
$this->assertFileExists($filename);
}

public function testTempnamWithZlibScheme()
{
$scheme = 'compress.zlib://';
$dirname = $scheme.$this->workspace;

$filename = $this->filesystem->tempnam($dirname, 'bar');

$this->assertNotFalse($filename);
$this->assertStringStartsWith($scheme, $filename);
// Zlib stat uses file:// wrapper so remove scheme
$this->assertFileExists(str_replace($scheme, '', $filename));
}

public function testTempnamWithHTTPSchemeFails()
{
$scheme = 'http://';
$dirname = $scheme.$this->workspace;

$filename = $this->filesystem->tempnam($dirname, 'bar');

$this->assertFalse($filename);
}

public function testTempnamOnUnwritableFallsBackToSysTmp()
{
$scheme = 'file://';
$dirname = $scheme.$this->workspace.DIRECTORY_SEPARATOR.'does_not_exist';

$filename = $this->filesystem->tempnam($dirname, 'bar');

$this->assertNotFalse($filename);
$this->assertStringStartsWith(rtrim($scheme.sys_get_temp_dir(), DIRECTORY_SEPARATOR), $filename);
$this->assertFileExists($filename);

// Tear down
unlink($filename);
}

public function testDumpFile()
{
$filename = $this->workspace.DIRECTORY_SEPARATOR.'foo'.DIRECTORY_SEPARATOR.'baz.txt';
Expand Down Expand Up @@ -1009,6 +1069,29 @@ public function testDumpFileOverwritesAnExistingFile()
$this->assertSame('bar', file_get_contents($filename));
}

public function testDumpFileWithFileScheme()
{
$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()
{
$sourceFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_source_file';
Expand Down
Morty Proxy This is a proxified and sanitized view of the page, visit original site.