Skip to content

Commit

Permalink
Add support for normalizing paths on FileProperty
Browse files Browse the repository at this point in the history
Added:
- Method `FileProperty::normalizePath()` to resolve relative paths while avoiding issues with the `realpath()` function

Changed:
- Method `ImageProperty::processEffectsOne()` to normalize paths

Example:
```
"thumbnail": {
    "type": "image",
    "upload_path": "uploads/thumbnails/src/",
    "effects": [
        {
            "type": "resize",
            "mode": "best_fit",
            "width": 150,
            "height": 150
        },
        {
            "type": "save",
            "copy": "../small/{{filename}}.{{extension}}"
        }
    ]
}
```
  • Loading branch information
mcaskill committed Nov 21, 2019
1 parent 23a388d commit e34058f
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 8 deletions.
58 changes: 58 additions & 0 deletions src/Charcoal/Property/FileProperty.php
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,13 @@ class FileProperty extends AbstractProperty
*/
private $filesystem = self::DEFAULT_FILESYSTEM;

/**
* Holds a list of all normalized paths.
*
* @var string[]
*/
protected static $normalizePathCache = [];

/**
* @return string
*/
Expand Down Expand Up @@ -1283,4 +1290,55 @@ public static function parseUploadedFiles(array $uploadedFiles, callable $filter

return $parsedFiles;
}

/**
* Normalize a file path string so that it can be checked safely.
*
* Attempt to avoid invalid encoding bugs by transcoding the path. Then
* remove any unnecessary path components including '.', '..' and ''.
*
* @link https://gist.github.com/thsutton/772287
*
* @param string $path The path to normalise.
* @param string $encoding The name of the path iconv() encoding.
* @return string The path, normalised.
*/
public static function normalizePath($path, $encoding = 'UTF-8')
{
$key = $path;

if (isset(static::$normalizePathCache[$key])) {
return static::$normalizePathCache[$key];
}

// Attempt to avoid path encoding problems.
$path = iconv($encoding, $encoding.'//IGNORE//TRANSLIT', $path);

if (strpos($path, '..') !== false || strpos($path, './') !== false) {
// Process the components
$parts = explode('/', $path);
$safe = [];
foreach ($parts as $idx => $part) {
if ((empty($part) && !is_numeric($part)) || ($part === '.')) {
continue;
} elseif ($part === '..') {
array_pop($safe);
continue;
} else {
$safe[] = $part;
}
}

// Return the "clean" path
$path = implode(DIRECTORY_SEPARATOR, $safe);

if ($key[0] === '/' && $path[0] !== '/') {
$path = '/'.$path;
}
}

static::$normalizePathCache[$key] = $path;

return static::$normalizePathCache[$key];
}
}
16 changes: 8 additions & 8 deletions src/Charcoal/Property/ImageProperty.php
Original file line number Diff line number Diff line change
Expand Up @@ -497,10 +497,10 @@ private function processEffectsOne($value, array $effects = null, ImageInterface

// @todo Save original file here
$valuePath = ($isAbsolute ? '' : $basePath);
$image->open($valuePath.$value);
$image->open(static::normalizePath($valuePath.$value));
$target = null;
if ($isAbsolute) {
$target = $basePath.$this['uploadPath'].pathinfo($value, PATHINFO_BASENAME);
$target = static::normalizePath($basePath.$this['uploadPath'].pathinfo($value, PATHINFO_BASENAME));
}

foreach ($effects as $fxGroup) {
Expand Down Expand Up @@ -545,13 +545,13 @@ private function processEffectsOne($value, array $effects = null, ImageInterface
if ($rename || $copy) {
if ($copy) {
$copy = $this->renderFileRenamePattern(($target ?: $value), $copy);
$exists = $this->fileExists($basePath.$copy);
$exists = $this->fileExists(static::normalizePath($basePath.$copy));
$doCopy = ($copy && ($this['overwrite'] || !$exists));
}

if ($rename) {
$value = $this->renderFileRenamePattern(($target ?: $value), $rename);
$exists = $this->fileExists($basePath.$value);
$exists = $this->fileExists(static::normalizePath($basePath.$value));
$doRename = ($value && ($this['overwrite'] || !$exists));
}

Expand All @@ -566,20 +566,20 @@ private function processEffectsOne($value, array $effects = null, ImageInterface

if ($rename || $copy) {
if ($doCopy) {
$image->save($valuePath.$copy);
$image->save(static::normalizePath($valuePath.$copy));
}

if ($doRename) {
$image->save($valuePath.$value);
$image->save(static::normalizePath($valuePath.$value));
}
} else {
$image->save($target ?: $valuePath.$value);
$image->save($target ?: static::normalizePath($valuePath.$value));
}
}
}
// reset to default image allow starting effects chains from original image.
if ($fxGroup['reset']) {
$image = $image->open($valuePath.$value);
$image = $image->open(static::normalizePath($valuePath.$value));
}
}
}
Expand Down

0 comments on commit e34058f

Please sign in to comment.