Skip to content

Commit 7a69e72

Browse files
Merge branch '3.4' into 4.0
* 3.4: fix merge [Security] Fix logout Cleanup 2 tests for the HttpException classes #27250 limiting GET_LOCK key up to 64 char due to changes in MySQL 5.7.5 and later [Config] Fix tests when path contains UTF chars [DI] Shared services should not be inlined in non-shared ones [Profiler] Remove propel & event_listener_loading category identifiers [Filesystem] Fix usages of error_get_last() [Cache][Lock] Fix usages of error_get_last() [Debug] Fix populating error_get_last() for handled silent errors [DI] Display previous error messages when throwing unused bindings Suppress warnings when open_basedir is non-empty
2 parents 1fa1d62 + 8e03ca3 commit 7a69e72

File tree

1 file changed

+43
-23
lines changed

1 file changed

+43
-23
lines changed

Filesystem.php

Lines changed: 43 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
*/
2323
class Filesystem
2424
{
25+
private static $lastError;
26+
2527
/**
2628
* Copies a file.
2729
*
@@ -96,12 +98,11 @@ public function mkdir($dirs, $mode = 0777)
9698
continue;
9799
}
98100

99-
if (true !== @mkdir($dir, $mode, true)) {
100-
$error = error_get_last();
101+
if (!self::box('mkdir', $dir, $mode, true)) {
101102
if (!is_dir($dir)) {
102103
// The directory was not created by a concurrent process. Let's throw an exception with a developer friendly error message if we have one
103-
if ($error) {
104-
throw new IOException(sprintf('Failed to create "%s": %s.', $dir, $error['message']), 0, null, $dir);
104+
if (self::$lastError) {
105+
throw new IOException(sprintf('Failed to create "%s": %s.', $dir, self::$lastError), 0, null, $dir);
105106
}
106107
throw new IOException(sprintf('Failed to create "%s"', $dir), 0, null, $dir);
107108
}
@@ -170,20 +171,17 @@ public function remove($files)
170171
foreach ($files as $file) {
171172
if (is_link($file)) {
172173
// See https://bugs.php.net/52176
173-
if (!@(unlink($file) || '\\' !== DIRECTORY_SEPARATOR || rmdir($file)) && file_exists($file)) {
174-
$error = error_get_last();
175-
throw new IOException(sprintf('Failed to remove symlink "%s": %s.', $file, $error['message']));
174+
if (!(self::box('unlink', $file) || '\\' !== DIRECTORY_SEPARATOR || self::box('rmdir', $file)) && file_exists($file)) {
175+
throw new IOException(sprintf('Failed to remove symlink "%s": %s.', $file, self::$lastError));
176176
}
177177
} elseif (is_dir($file)) {
178178
$this->remove(new \FilesystemIterator($file, \FilesystemIterator::CURRENT_AS_PATHNAME | \FilesystemIterator::SKIP_DOTS));
179179

180-
if (!@rmdir($file) && file_exists($file)) {
181-
$error = error_get_last();
182-
throw new IOException(sprintf('Failed to remove directory "%s": %s.', $file, $error['message']));
180+
if (!self::box('rmdir', $file) && file_exists($file)) {
181+
throw new IOException(sprintf('Failed to remove directory "%s": %s.', $file, self::$lastError));
183182
}
184-
} elseif (!@unlink($file) && file_exists($file)) {
185-
$error = error_get_last();
186-
throw new IOException(sprintf('Failed to remove file "%s": %s.', $file, $error['message']));
183+
} elseif (!self::box('unlink', $file) && file_exists($file)) {
184+
throw new IOException(sprintf('Failed to remove file "%s": %s.', $file, self::$lastError));
187185
}
188186
}
189187
}
@@ -337,16 +335,14 @@ public function symlink($originDir, $targetDir, $copyOnWindows = false)
337335

338336
$this->mkdir(dirname($targetDir));
339337

340-
$ok = false;
341338
if (is_link($targetDir)) {
342-
if (readlink($targetDir) != $originDir) {
343-
$this->remove($targetDir);
344-
} else {
345-
$ok = true;
339+
if (readlink($targetDir) === $originDir) {
340+
return;
346341
}
342+
$this->remove($targetDir);
347343
}
348344

349-
if (!$ok && true !== @symlink($originDir, $targetDir)) {
345+
if (!self::box('symlink', $originDir, $targetDir)) {
350346
$this->linkException($originDir, $targetDir, 'symbolic');
351347
}
352348
}
@@ -378,7 +374,7 @@ public function hardlink($originFile, $targetFiles)
378374
$this->remove($targetFile);
379375
}
380376

381-
if (true !== @link($originFile, $targetFile)) {
377+
if (!self::box('link', $originFile, $targetFile)) {
382378
$this->linkException($originFile, $targetFile, 'hard');
383379
}
384380
}
@@ -391,9 +387,8 @@ public function hardlink($originFile, $targetFiles)
391387
*/
392388
private function linkException($origin, $target, $linkType)
393389
{
394-
$report = error_get_last();
395-
if (is_array($report)) {
396-
if ('\\' === DIRECTORY_SEPARATOR && false !== strpos($report['message'], 'error code(1314)')) {
390+
if (self::$lastError) {
391+
if ('\\' === DIRECTORY_SEPARATOR && false !== strpos(self::$lastError, 'error code(1314)')) {
397392
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);
398393
}
399394
}
@@ -743,4 +738,29 @@ private function getSchemeAndHierarchy(string $filename): array
743738

744739
return 2 === count($components) ? array($components[0], $components[1]) : array(null, $components[0]);
745740
}
741+
742+
private static function box($func)
743+
{
744+
self::$lastError = null;
745+
\set_error_handler(__CLASS__.'::handleError');
746+
try {
747+
$result = \call_user_func_array($func, \array_slice(\func_get_args(), 1));
748+
\restore_error_handler();
749+
750+
return $result;
751+
} catch (\Throwable $e) {
752+
} catch (\Exception $e) {
753+
}
754+
\restore_error_handler();
755+
756+
throw $e;
757+
}
758+
759+
/**
760+
* @internal
761+
*/
762+
public static function handleError($type, $msg)
763+
{
764+
self::$lastError = $msg;
765+
}
746766
}

0 commit comments

Comments
 (0)