namespace Symfony\Component\Filesystem;
-use Symfony\Component\Filesystem\Exception\IOException;
use Symfony\Component\Filesystem\Exception\FileNotFoundException;
+use Symfony\Component\Filesystem\Exception\IOException;
/**
* Provides basic utility to manipulate the file system.
*/
class Filesystem
{
+ private static $lastError;
+
/**
* Copies a file.
*
throw new FileNotFoundException(sprintf('Failed to copy "%s" because file does not exist.', $originFile), 0, null, $originFile);
}
- $this->mkdir(dirname($targetFile));
+ $this->mkdir(\dirname($targetFile));
$doCopy = true;
if (!$overwriteNewerFiles && null === parse_url($originFile, PHP_URL_HOST) && is_file($targetFile)) {
continue;
}
- if (true !== @mkdir($dir, $mode, true)) {
- $error = error_get_last();
+ if (!self::box('mkdir', $dir, $mode, true)) {
if (!is_dir($dir)) {
// The directory was not created by a concurrent process. Let's throw an exception with a developer friendly error message if we have one
- if ($error) {
- throw new IOException(sprintf('Failed to create "%s": %s.', $dir, $error['message']), 0, null, $dir);
+ if (self::$lastError) {
+ throw new IOException(sprintf('Failed to create "%s": %s.', $dir, self::$lastError), 0, null, $dir);
}
throw new IOException(sprintf('Failed to create "%s"', $dir), 0, null, $dir);
}
$maxPathLength = PHP_MAXPATHLEN - 2;
foreach ($this->toIterable($files) as $file) {
- if (strlen($file) > $maxPathLength) {
+ if (\strlen($file) > $maxPathLength) {
throw new IOException(sprintf('Could not check if file exist because path length exceeds %d characters.', $maxPathLength), 0, null, $file);
}
{
if ($files instanceof \Traversable) {
$files = iterator_to_array($files, false);
- } elseif (!is_array($files)) {
+ } elseif (!\is_array($files)) {
$files = array($files);
}
$files = array_reverse($files);
foreach ($files as $file) {
if (is_link($file)) {
// See https://bugs.php.net/52176
- if (!@(unlink($file) || '\\' !== DIRECTORY_SEPARATOR || rmdir($file)) && file_exists($file)) {
- $error = error_get_last();
- throw new IOException(sprintf('Failed to remove symlink "%s": %s.', $file, $error['message']));
+ if (!(self::box('unlink', $file) || '\\' !== \DIRECTORY_SEPARATOR || self::box('rmdir', $file)) && file_exists($file)) {
+ throw new IOException(sprintf('Failed to remove symlink "%s": %s.', $file, self::$lastError));
}
} elseif (is_dir($file)) {
$this->remove(new \FilesystemIterator($file, \FilesystemIterator::CURRENT_AS_PATHNAME | \FilesystemIterator::SKIP_DOTS));
- if (!@rmdir($file) && file_exists($file)) {
- $error = error_get_last();
- throw new IOException(sprintf('Failed to remove directory "%s": %s.', $file, $error['message']));
+ if (!self::box('rmdir', $file) && file_exists($file)) {
+ throw new IOException(sprintf('Failed to remove directory "%s": %s.', $file, self::$lastError));
}
- } elseif (!@unlink($file) && file_exists($file)) {
- $error = error_get_last();
- throw new IOException(sprintf('Failed to remove file "%s": %s.', $file, $error['message']));
+ } elseif (!self::box('unlink', $file) && file_exists($file)) {
+ throw new IOException(sprintf('Failed to remove file "%s": %s.', $file, self::$lastError));
}
}
}
if ($recursive && is_dir($file) && !is_link($file)) {
$this->chown(new \FilesystemIterator($file), $user, true);
}
- if (is_link($file) && function_exists('lchown')) {
+ if (is_link($file) && \function_exists('lchown')) {
if (true !== @lchown($file, $user)) {
throw new IOException(sprintf('Failed to chown file "%s".', $file), 0, null, $file);
}
if ($recursive && is_dir($file) && !is_link($file)) {
$this->chgrp(new \FilesystemIterator($file), $group, true);
}
- if (is_link($file) && function_exists('lchgrp')) {
- if (true !== @lchgrp($file, $group) || (defined('HHVM_VERSION') && !posix_getgrnam($group))) {
+ if (is_link($file) && \function_exists('lchgrp')) {
+ if (true !== @lchgrp($file, $group) || (\defined('HHVM_VERSION') && !posix_getgrnam($group))) {
throw new IOException(sprintf('Failed to chgrp file "%s".', $file), 0, null, $file);
}
} else {
{
$maxPathLength = PHP_MAXPATHLEN - 2;
- if (strlen($filename) > $maxPathLength) {
+ if (\strlen($filename) > $maxPathLength) {
throw new IOException(sprintf('Could not check if file is readable because path length exceeds %d characters.', $maxPathLength), 0, null, $filename);
}
*/
public function symlink($originDir, $targetDir, $copyOnWindows = false)
{
- if ('\\' === DIRECTORY_SEPARATOR) {
+ if ('\\' === \DIRECTORY_SEPARATOR) {
$originDir = strtr($originDir, '/', '\\');
$targetDir = strtr($targetDir, '/', '\\');
}
}
- $this->mkdir(dirname($targetDir));
+ $this->mkdir(\dirname($targetDir));
- $ok = false;
if (is_link($targetDir)) {
- if (readlink($targetDir) != $originDir) {
- $this->remove($targetDir);
- } else {
- $ok = true;
+ if (readlink($targetDir) === $originDir) {
+ return;
}
+ $this->remove($targetDir);
}
- if (!$ok && true !== @symlink($originDir, $targetDir)) {
+ if (!self::box('symlink', $originDir, $targetDir)) {
$this->linkException($originDir, $targetDir, 'symbolic');
}
}
$this->remove($targetFile);
}
- if (true !== @link($originFile, $targetFile)) {
+ if (!self::box('link', $originFile, $targetFile)) {
$this->linkException($originFile, $targetFile, 'hard');
}
}
*/
private function linkException($origin, $target, $linkType)
{
- $report = error_get_last();
- if (is_array($report)) {
- if ('\\' === DIRECTORY_SEPARATOR && false !== strpos($report['message'], 'error code(1314)')) {
+ if (self::$lastError) {
+ if ('\\' === \DIRECTORY_SEPARATOR && false !== strpos(self::$lastError, 'error code(1314)')) {
throw new IOException(sprintf('Unable to create %s link due to error code 1314: \'A required privilege is not held by the client\'. Do you have the required Administrator-rights?', $linkType), 0, null, $target);
}
}
return;
}
- if ('\\' === DIRECTORY_SEPARATOR) {
+ if ('\\' === \DIRECTORY_SEPARATOR) {
$path = readlink($path);
}
return realpath($path);
}
- if ('\\' === DIRECTORY_SEPARATOR) {
+ if ('\\' === \DIRECTORY_SEPARATOR) {
return realpath($path);
}
}
// Normalize separators on Windows
- if ('\\' === DIRECTORY_SEPARATOR) {
+ if ('\\' === \DIRECTORY_SEPARATOR) {
$endPath = str_replace('\\', '/', $endPath);
$startPath = str_replace('\\', '/', $startPath);
}
$stripDriveLetter = function ($path) {
- if (strlen($path) > 2 && ':' === $path[1] && '/' === $path[2] && ctype_alpha($path[0])) {
+ if (\strlen($path) > 2 && ':' === $path[1] && '/' === $path[2] && ctype_alpha($path[0])) {
return substr($path, 2);
}
$result = array();
foreach ($pathSegments as $segment) {
- if ('..' === $segment && ($absolute || count($result))) {
+ if ('..' === $segment && ($absolute || \count($result))) {
array_pop($result);
} elseif ('.' !== $segment) {
$result[] = $segment;
}
// Determine how deep the start path is relative to the common path (ie, "web/bundles" = 2 levels)
- if (1 === count($startPathArr) && '' === $startPathArr[0]) {
+ if (1 === \count($startPathArr) && '' === $startPathArr[0]) {
$depth = 0;
} else {
- $depth = count($startPathArr) - $index;
+ $depth = \count($startPathArr) - $index;
}
// Repeated "../" for each level need to reach the common path
$traverser = str_repeat('../', $depth);
- $endPathRemainder = implode('/', array_slice($endPathArr, $index));
+ $endPathRemainder = implode('/', \array_slice($endPathArr, $index));
// Construct $endPath from traversing to the common path, then to the remaining $endPath
$relativePath = $traverser.('' !== $endPathRemainder ? $endPathRemainder.'/' : '');
{
$targetDir = rtrim($targetDir, '/\\');
$originDir = rtrim($originDir, '/\\');
- $originDirLen = strlen($originDir);
+ $originDirLen = \strlen($originDir);
// Iterate in destination folder to remove obsolete entries
if ($this->exists($targetDir) && isset($options['delete']) && $options['delete']) {
$flags = \FilesystemIterator::SKIP_DOTS;
$deleteIterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($targetDir, $flags), \RecursiveIteratorIterator::CHILD_FIRST);
}
- $targetDirLen = strlen($targetDir);
+ $targetDirLen = \strlen($targetDir);
foreach ($deleteIterator as $file) {
$origin = $originDir.substr($file->getPathname(), $targetDirLen);
if (!$this->exists($origin)) {
public function isAbsolutePath($file)
{
return strspn($file, '/\\', 0, 1)
- || (strlen($file) > 3 && ctype_alpha($file[0])
+ || (\strlen($file) > 3 && ctype_alpha($file[0])
&& ':' === $file[1]
&& strspn($file, '/\\', 2, 1)
)
*/
public function dumpFile($filename, $content)
{
- $dir = dirname($filename);
+ $dir = \dirname($filename);
if (!is_dir($dir)) {
$this->mkdir($dir);
*/
public function appendToFile($filename, $content)
{
- $dir = dirname($filename);
+ $dir = \dirname($filename);
if (!is_dir($dir)) {
$this->mkdir($dir);
*/
private function toIterable($files)
{
- return is_array($files) || $files instanceof \Traversable ? $files : array($files);
+ return \is_array($files) || $files instanceof \Traversable ? $files : array($files);
}
/**
{
$components = explode('://', $filename, 2);
- return 2 === count($components) ? array($components[0], $components[1]) : array(null, $components[0]);
+ return 2 === \count($components) ? array($components[0], $components[1]) : array(null, $components[0]);
+ }
+
+ private static function box($func)
+ {
+ self::$lastError = null;
+ \set_error_handler(__CLASS__.'::handleError');
+ try {
+ $result = \call_user_func_array($func, \array_slice(\func_get_args(), 1));
+ \restore_error_handler();
+
+ return $result;
+ } catch (\Throwable $e) {
+ } catch (\Exception $e) {
+ }
+ \restore_error_handler();
+
+ throw $e;
+ }
+
+ /**
+ * @internal
+ */
+ public static function handleError($type, $msg)
+ {
+ self::$lastError = $msg;
}
}