Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
57 changes: 49 additions & 8 deletions src/controllers/AssetsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,12 @@
use craft\fields\Assets as AssetsField;
use craft\helpers\Assets;
use craft\helpers\Db;
use craft\helpers\FileHelper;
use craft\helpers\Image;
use craft\models\Volume;
use craft\web\Controller;
use DateTime;
use Throwable;
use yii\base\Event;
use yii\base\Exception;
use yii\base\Model;
Expand Down Expand Up @@ -95,8 +98,6 @@ public function actionCreateAsset(): Response
$originalFilename = $this->request->getRequiredBodyParam('originalFilename');
$targetFilename = $this->request->getRequiredBodyParam('targetFilename');
$size = $this->request->getBodyParam('size');
$width = $this->request->getBodyParam('width');
$height = $this->request->getBodyParam('height');
$elementsService = Craft::$app->getElements();
$lastModifiedMs = (int) $this->request->getBodyParam('lastModified');
$dateModified = $lastModifiedMs
Expand Down Expand Up @@ -160,8 +161,6 @@ public function actionCreateAsset(): Response
$asset->avoidFilenameConflicts = true;
$asset->dateModified = $dateModified;
$asset->size = $size;
$asset->width = $width;
$asset->height = $height;

// Setting newFolderId, so that extension validation on newLocation occurs
$asset->newFolderId = $folder->id;
Expand All @@ -172,6 +171,8 @@ public function actionCreateAsset(): Response
// Handle special characters that have been encoded from the presigned URL
$asset->folderPath = is_string($folder->path) ? Fs::urlEncodePathSegments($folder->path) : $asset->folderPath;

[$asset->width, $asset->height] = $this->uploadedImageDimensions($asset, $filename);

if (!$selectionCondition) {
$asset->newFilename = $targetFilename;
}
Expand Down Expand Up @@ -240,8 +241,6 @@ public function actionReplaceFile(): Response
$filename = $this->request->getBodyParam('filename');
$targetFilename = $this->request->getBodyParam('targetFilename');
$size = $this->request->getBodyParam('size');
$width = $this->request->getBodyParam('width');
$height = $this->request->getBodyParam('height');
$lastModifiedMs = (int) $this->request->getBodyParam('lastModified');
$dateModified = $lastModifiedMs
? DateTime::createFromFormat('U', (string) floor($lastModifiedMs / 1000))
Expand Down Expand Up @@ -272,8 +271,6 @@ public function actionReplaceFile(): Response

// Handle the Element Action
if ($assetToReplace !== null && $filename) {
$assetToReplace->width = $width;
$assetToReplace->height = $height;
$assetToReplace->size = $size;
$assetToReplace->dateModified = $dateModified;
if (!$this->replaceAssetFile($assetToReplace, $filename, $targetFilename)) {
Expand Down Expand Up @@ -357,6 +354,7 @@ public function replaceAssetFile(Asset $asset, string $filename, string $targetF
$asset->avoidFilenameConflicts = true;
$asset->setScenario(Asset::SCENARIO_REPLACE);
$asset->setFilename($filename);
[$asset->width, $asset->height] = $this->uploadedImageDimensions($asset, $filename);
$asset->newFilename = $targetFilename;

$saved = $this->saveAsset($asset);
Expand Down Expand Up @@ -396,4 +394,47 @@ private function volumeSubpath(Volume $volume): string
{
return method_exists($volume, 'getSubpath') ? $volume->getSubpath() : '';
}

protected function uploadedImageDimensions(Asset $asset, string $filename): array
{
if (Assets::getFileKindByExtension($filename) !== Asset::KIND_IMAGE) {
return [null, null];
}

return $this->readUploadedImageDimensions($asset) ?? [null, null];
}

protected function readUploadedImageDimensions(Asset $asset): ?array
{
$stream = null;
$tempPath = null;

try {
$stream = $asset->getVolume()->getFs()->getFileStream($asset->getPath());
$imageSize = Image::imageSizeByStream($stream);
Comment thread
timkelty marked this conversation as resolved.

if ($imageSize === false || !isset($imageSize[0], $imageSize[1])) {
fclose($stream);
$stream = null;

$tempPath = $asset->getCopyOfFile();
$imageSize = Image::imageSize($tempPath);
}

return [
(int)$imageSize[0] ?: null,
(int)$imageSize[1] ?: null,
];
} catch (Throwable) {
return null;
} finally {
if (is_resource($stream)) {
fclose($stream);
}

if ($tempPath !== null) {
FileHelper::unlink($tempPath);
}
}
}
}
6 changes: 3 additions & 3 deletions src/fs/Fs.php
Original file line number Diff line number Diff line change
Expand Up @@ -94,20 +94,20 @@ public function createUrl(string $path = ''): UriInterface
{
if ($this->useLocalFs) {
return Modifier::wrap($this->getLocalFs()->getRootUrl() ?? '/')
->appendSegment($this->createPath($path))
->appendPath($this->createPath($path))
->unwrap();
}

$baseUrl = App::parseEnv($this->baseUrl);

if ($baseUrl) {
return Modifier::wrap($baseUrl)
->appendSegment($this->createPath($path))
->appendPath($this->createPath($path))
->unwrap();
}

return Modifier::wrap(Module::getInstance()->getConfig()->cdnBaseUrl)
->appendSegment($this->createBucketPath($path))
->appendPath($this->createBucketPath($path))
->unwrap();
}

Expand Down
71 changes: 71 additions & 0 deletions tests/unit/AssetsControllerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use Codeception\Test\Unit;
use Craft;
use craft\cloud\controllers\AssetsController;
use craft\elements\Asset;
use craft\models\Volume;
use ReflectionMethod;

Expand Down Expand Up @@ -39,6 +40,56 @@ public function testVolumeSubpathReturnsVolumeSubpathOnCraft5(): void
$this->assertSame('volume-prefix/', $this->invokeVolumeSubpath($volume));
}

public function testImageUploadsUseUploadedImageDimensions(): void
{
$controller = new DimensionTestAssetsController('cloud-assets', Craft::$app);
$controller->uploadedImageDimensions = [2139, 3020];

$this->assertSame([2139, 3020], $controller->uploadedImageDimensionsForTest(
new Asset(),
'upload.jpeg',
));
$this->assertSame(1, $controller->readCount);
}

public function testImageUploadsUseNullDimensionsWhenUploadedImageDimensionsCannotBeRead(): void
{
$controller = new DimensionTestAssetsController('cloud-assets', Craft::$app);

$this->assertSame([null, null], $controller->uploadedImageDimensionsForTest(
new Asset(),
'upload.jpeg',
));
$this->assertSame(1, $controller->readCount);
}

public function testNonImageUploadsUseNullDimensions(): void
{
$controller = new DimensionTestAssetsController('cloud-assets', Craft::$app);
$controller->uploadedImageDimensions = [2139, 3020];

$this->assertSame([null, null], $controller->uploadedImageDimensionsForTest(
new Asset(),
'document.pdf',
));
$this->assertSame(0, $controller->readCount);
}

public function testReplacementUploadsUseServerDimensionsForUploadedFile(): void
{
$asset = new Asset();
$asset->folderPath = 'uploads';

$controller = new DimensionTestAssetsController('cloud-assets', Craft::$app);
$controller->uploadedImageDimensions = [1080, 1440];

$this->assertSame([1080, 1440], $controller->uploadedImageDimensionsForTest(
$asset,
'upload-replacement.jpeg',
));
$this->assertSame(1, $controller->readCount);
}

private function invokeVolumeSubpath(Volume $volume): string
{
$controller = new AssetsController('cloud-assets', Craft::$app);
Expand All @@ -48,3 +99,23 @@ private function invokeVolumeSubpath(Volume $volume): string
return $method->invoke($controller, $volume);
}
}

class DimensionTestAssetsController extends AssetsController
{
public ?array $uploadedImageDimensions = null;
public int $readCount = 0;

public function uploadedImageDimensionsForTest(Asset $asset, string $filename): array
{
$asset->setFilename($filename);

return $this->uploadedImageDimensions($asset, $filename);
}

protected function readUploadedImageDimensions(Asset $asset): ?array
{
$this->readCount++;

return $this->uploadedImageDimensions;
}
}
Loading