Skip to content

Commit 51b01e0

Browse files
committed
ACP2E-502: Filename is too long exception when importing media images
1 parent 06be96e commit 51b01e0

File tree

6 files changed

+172
-22
lines changed

6 files changed

+172
-22
lines changed
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!--
3+
/**
4+
* Copyright © Magento, Inc. All rights reserved.
5+
* See COPYING.txt for license details.
6+
*/
7+
-->
8+
9+
<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
10+
xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd">
11+
<test name="AdminImportSimpleProductImageLongNameTest">
12+
<annotations>
13+
<features value="Import/Export"/>
14+
<stories value="Import Products"/>
15+
<title value="Import product with long image filename"/>
16+
<description value="Import product with long image filename should not cause errors"/>
17+
<severity value="MAJOR"/>
18+
<testCaseId value="ACP2E-502"/>
19+
<useCaseId value="AC-2676"/>
20+
<group value="catalog_import_export"/>
21+
</annotations>
22+
23+
<before>
24+
<!-- Create Simple Product -->
25+
<createData entity="_defaultCategory" stepKey="createCategory"/>
26+
<createData entity="SimpleProduct" stepKey="createProduct">
27+
<field key="sku">test_image_long_name_sku</field>
28+
<requiredEntity createDataKey="createCategory"/>
29+
</createData>
30+
<!-- Copy Image to Import Directory for Product Images -->
31+
<helper class="Magento\Catalog\Test\Mftf\Helper\LocalFileAssertions" method="createDirectory" stepKey="createDirectoryForImportImages">
32+
<argument name="path">var/import/images/test_image_long_name</argument>
33+
</helper>
34+
<helper class="Magento\Catalog\Test\Mftf\Helper\LocalFileAssertions" method="copy" stepKey="copyProductBaseImage">
35+
<argument name="source">dev/tests/acceptance/tests/_data/{{placeholderBaseImage.file}}</argument>
36+
<argument name="destination">var/import/images/test_image_long_name/{{placeholderBaseImage.file}}</argument>
37+
</helper>
38+
<!-- Login as Admin -->
39+
<actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/>
40+
</before>
41+
42+
<after>
43+
<deleteData createDataKey="createProduct" stepKey="deleteProduct"/>
44+
<deleteData createDataKey="createCategory" stepKey="deleteCategory"/>
45+
<helper class="Magento\Catalog\Test\Mftf\Helper\LocalFileAssertions" method="deleteDirectory" stepKey="deleteProductImageDirectory">
46+
<argument name="path">var/import/images/test_image_long_name</argument>
47+
</helper>
48+
<actionGroup ref="AdminLogoutActionGroup" stepKey="logoutFromAdmin"/>
49+
</after>
50+
51+
<!-- Import product with add/update behavior -->
52+
<actionGroup ref="AdminImportProductsWithCustomImagesDirectoryActionGroup" stepKey="importCSVFile">
53+
<argument name="behavior" value="Add/Update"/>
54+
<argument name="importFile" value="import_simple_product_with_image_long_name.csv"/>
55+
<argument name="imagesFileDirectory" value="test_image_long_name"/>
56+
<argument name="importNoticeMessage" value="Created: 0, Updated: 1, Deleted: 0"/>
57+
</actionGroup>
58+
<!-- Verify image -->
59+
<actionGroup ref="AdminProductPageOpenByIdActionGroup" stepKey="openProduct">
60+
<argument name="productId" value="$createProduct.id$"/>
61+
</actionGroup>
62+
<actionGroup ref="AdminAssertProductImageOnProductPageActionGroup" stepKey="assertBaseImageIsPresent">
63+
<argument name="image" value="{{placeholderBaseImage.name}}"/>
64+
</actionGroup>
65+
</test>
66+
</tests>

app/code/Magento/MediaStorage/Model/ResourceModel/File/Storage/Database.php

Lines changed: 90 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,17 @@
55
*/
66
namespace Magento\MediaStorage\Model\ResourceModel\File\Storage;
77

8+
use Magento\Framework\App\DeploymentConfig;
9+
use Magento\Framework\App\ObjectManager;
10+
use Magento\Framework\Config\ConfigOptionsListConstants;
11+
use Magento\Framework\App\ResourceConnection\ConnectionFactory;
12+
use Magento\Framework\DB\Ddl\Table;
13+
use Magento\Framework\DB\Adapter\AdapterInterface;
14+
use Magento\Framework\DB\Helper;
15+
use Magento\Framework\Model\ResourceModel\Db\Context;
16+
817
/**
9-
* Class Database
18+
* Class Database Media Storage
1019
*
1120
* @api
1221
* @since 100.0.2
@@ -21,17 +30,46 @@ class Database extends \Magento\MediaStorage\Model\ResourceModel\File\Storage\Ab
2130
protected $_resourceHelper;
2231

2332
/**
24-
* @param \Magento\Framework\Model\ResourceModel\Db\Context $context
25-
* @param \Magento\Framework\DB\Helper $resourceHelper
33+
* @var ConnectionFactory
34+
*/
35+
private $connectionFactory;
36+
37+
/**
38+
* @var DeploymentConfig
39+
*/
40+
private $deploymentConfig;
41+
42+
/**
43+
* @var array
44+
*/
45+
private array $filenameColumn = [
46+
'name' => 'filename',
47+
'type' => Table::TYPE_TEXT,
48+
'length' => 255,
49+
'nullable' => false,
50+
'comment' => 'Filename',
51+
];
52+
53+
/**
54+
* @param Context $context
55+
* @param Helper $resourceHelper
2656
* @param string $connectionName
57+
* @param ConnectionFactory|null $connectionFactory
58+
* @param DeploymentConfig|null $deploymentConfig
2759
*/
2860
public function __construct(
29-
\Magento\Framework\Model\ResourceModel\Db\Context $context,
30-
\Magento\Framework\DB\Helper $resourceHelper,
31-
$connectionName = null
61+
Context $context,
62+
Helper $resourceHelper,
63+
string $connectionName = null,
64+
ConnectionFactory $connectionFactory = null,
65+
DeploymentConfig $deploymentConfig = null
3266
) {
3367
parent::__construct($context, $connectionName);
3468
$this->_resourceHelper = $resourceHelper;
69+
$this->connectionFactory = $connectionFactory
70+
?? ObjectManager::getInstance()->get(ConnectionFactory::class);
71+
$this->deploymentConfig = $deploymentConfig
72+
?? ObjectManager::getInstance()->get(DeploymentConfig::class);
3573
}
3674

3775
/**
@@ -54,6 +92,7 @@ public function createDatabaseScheme()
5492
$connection = $this->getConnection();
5593
$table = $this->getMainTable();
5694
if ($connection->isTableExists($table)) {
95+
$this->increaseLengthFilenameColumn();
5796
return $this;
5897
}
5998

@@ -81,11 +120,11 @@ public function createDatabaseScheme()
81120
['nullable' => false, 'default' => \Magento\Framework\DB\Ddl\Table::TIMESTAMP_INIT],
82121
'Upload Timestamp'
83122
)->addColumn(
84-
'filename',
85-
\Magento\Framework\DB\Ddl\Table::TYPE_TEXT,
86-
100,
87-
['nullable' => false],
88-
'Filename'
123+
$this->filenameColumn['name'],
124+
$this->filenameColumn['type'],
125+
$this->filenameColumn['length'],
126+
['nullable' => $this->filenameColumn['nullable']],
127+
$this->filenameColumn['comment']
89128
)->addColumn(
90129
'directory_id',
91130
\Magento\Framework\DB\Ddl\Table::TYPE_INTEGER,
@@ -123,6 +162,46 @@ public function createDatabaseScheme()
123162
return $this;
124163
}
125164

165+
/**
166+
* Create new DB connection
167+
*
168+
* @param string $connectionName
169+
* @return AdapterInterface
170+
*/
171+
private function createResourceConnection(?string $connectionName): AdapterInterface
172+
{
173+
$connectionName = $connectionName ?: $this->connectionName;
174+
$connectionConfig = $this->deploymentConfig->get(
175+
ConfigOptionsListConstants::CONFIG_PATH_DB_CONNECTIONS . '/' . $connectionName
176+
);
177+
return $this->connectionFactory->create($connectionConfig);
178+
}
179+
180+
/**
181+
* Increase length of filename column
182+
*
183+
* @return void
184+
*/
185+
private function increaseLengthFilenameColumn(): void
186+
{
187+
$connection = $this->createResourceConnection($this->connectionName);
188+
$table = $this->getMainTable();
189+
$columns = $connection->describeTable($table);
190+
$filenameLength = $columns['filename']['LENGTH'] ?? null;
191+
if ($filenameLength && $filenameLength < $this->filenameColumn['length']) {
192+
$connection->modifyColumn(
193+
$table,
194+
$this->filenameColumn['name'],
195+
[
196+
'type' => $this->filenameColumn['type'],
197+
'length' => $this->filenameColumn['length'],
198+
'nullable' => $this->filenameColumn['nullable'],
199+
'comment' => $this->filenameColumn['comment'],
200+
]
201+
);
202+
}
203+
}
204+
126205
/**
127206
* Decodes blob content retrieved by DB driver
128207
*
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
sku,base_image
2+
"test_image_long_name_sku","adobe-base-image-long-name-image-long-name-image-long-name-image-long-name-image-long-name-image-long-name-image-long-name-image-long-name-image-long-name.jpg"

lib/internal/Magento/Framework/File/Test/Unit/UploaderTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ public function getCorrectFileNameProvider()
6262
'a.' . str_repeat('b', 88)
6363
],
6464
[
65-
'a.' . str_repeat('b', 89),
65+
'a.' . str_repeat('b', 256),
6666
true
6767
]
6868
];

lib/internal/Magento/Framework/File/Uploader.php

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
*
2525
* @SuppressWarnings(PHPMD.TooManyFields)
2626
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
27+
* @SuppressWarnings(PHPMD.ExcessiveClassComplexity)
2728
*
2829
* @api
2930
* @since 100.0.2
@@ -148,28 +149,33 @@ class Uploader
148149
/**#@+
149150
* File upload type (multiple or single)
150151
*/
151-
const SINGLE_STYLE = 0;
152+
public const SINGLE_STYLE = 0;
152153

153-
const MULTIPLE_STYLE = 1;
154+
public const MULTIPLE_STYLE = 1;
154155

155156
/**#@-*/
156157

157158
/**
158159
* Temp file name empty code
159160
*/
160-
const TMP_NAME_EMPTY = 666;
161+
public const TMP_NAME_EMPTY = 666;
161162

162163
/**
163164
* Maximum Image Width resolution in pixels. For image resizing on client side
164165
* @deprecated @see \Magento\Framework\Image\Adapter\UploadConfigInterface::getMaxWidth()
165166
*/
166-
const MAX_IMAGE_WIDTH = 1920;
167+
public const MAX_IMAGE_WIDTH = 1920;
167168

168169
/**
169170
* Maximum Image Height resolution in pixels. For image resizing on client side
170171
* @deprecated @see \Magento\Framework\Image\Adapter\UploadConfigInterface::getMaxHeight()
171172
*/
172-
const MAX_IMAGE_HEIGHT = 1200;
173+
public const MAX_IMAGE_HEIGHT = 1200;
174+
175+
/**
176+
* Maximum file name length
177+
*/
178+
private const MAX_FILE_NAME_LENGTH = 255;
173179

174180
/**
175181
* Resulting of uploaded file
@@ -495,12 +501,9 @@ public static function getCorrectFileName($fileName)
495501
$fileInfo = pathinfo($fileName);
496502
$fileInfo['extension'] = $fileInfo['extension'] ?? '';
497503

498-
// account for excessively long filenames that cannot be stored completely in database
499-
$maxFilenameLength = 90;
500-
501-
if (strlen($fileInfo['basename']) > $maxFilenameLength) {
504+
if (strlen($fileInfo['basename']) > self::MAX_FILE_NAME_LENGTH) {
502505
throw new \LengthException(
503-
__('Filename is too long; must be %1 characters or less', $maxFilenameLength)
506+
__('Filename is too long; must be %1 characters or less', self::MAX_FILE_NAME_LENGTH)
504507
);
505508
}
506509

0 commit comments

Comments
 (0)