Skip to content

Commit 13cef1b

Browse files
committed
AC-14331: Customer address attribute enhancement
1 parent b5b3714 commit 13cef1b

File tree

4 files changed

+248
-22
lines changed

4 files changed

+248
-22
lines changed

app/code/Magento/Customer/Controller/Address/FormPost.php

Lines changed: 53 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,34 @@
11
<?php
22
/**
3-
* Copyright © Magento, Inc. All rights reserved.
4-
* See COPYING.txt for license details.
3+
* Copyright 2014 Adobe
4+
* All Rights Reserved.
55
*/
66

77
namespace Magento\Customer\Controller\Address;
88

9-
use Magento\Framework\App\Action\HttpPostActionInterface as HttpPostActionInterface;
9+
use Magento\Customer\Api\AddressMetadataInterface;
1010
use Magento\Customer\Api\AddressRepositoryInterface;
1111
use Magento\Customer\Api\Data\AddressInterfaceFactory;
1212
use Magento\Customer\Api\Data\RegionInterface;
1313
use Magento\Customer\Api\Data\RegionInterfaceFactory;
1414
use Magento\Customer\Model\Address\Mapper;
1515
use Magento\Customer\Model\Metadata\FormFactory;
1616
use Magento\Customer\Model\Session;
17+
use Magento\Customer\Model\Validator\Address\File as FileNameValidator;
1718
use Magento\Directory\Helper\Data as HelperData;
1819
use Magento\Directory\Model\RegionFactory;
1920
use Magento\Framework\Api\DataObjectHelper;
2021
use Magento\Framework\App\Action\Context;
22+
use Magento\Framework\App\Action\HttpPostActionInterface as HttpPostActionInterface;
23+
use Magento\Framework\App\Filesystem\DirectoryList;
2124
use Magento\Framework\App\ObjectManager;
2225
use Magento\Framework\Controller\Result\ForwardFactory;
2326
use Magento\Framework\Data\Form\FormKey\Validator as FormKeyValidator;
2427
use Magento\Framework\Exception\InputException;
28+
use Magento\Framework\Exception\NotFoundException;
29+
use Magento\Framework\Filesystem;
2530
use Magento\Framework\Reflection\DataObjectProcessor;
2631
use Magento\Framework\View\Result\PageFactory;
27-
use Magento\Framework\Filesystem;
28-
use Magento\Framework\App\Filesystem\DirectoryList;
29-
use Magento\Framework\Exception\NotFoundException;
3032

3133
/**
3234
* Customer Address Form Post Controller
@@ -55,6 +57,16 @@ class FormPost extends \Magento\Customer\Controller\Address implements HttpPostA
5557
*/
5658
private $filesystem;
5759

60+
/**
61+
* @var AddressMetadataInterface
62+
*/
63+
private $addressMetadata;
64+
65+
/**
66+
* @var FileNameValidator
67+
*/
68+
private $fileNameValidator;
69+
5870
/**
5971
* @param Context $context
6072
* @param Session $customerSession
@@ -69,7 +81,9 @@ class FormPost extends \Magento\Customer\Controller\Address implements HttpPostA
6981
* @param PageFactory $resultPageFactory
7082
* @param RegionFactory $regionFactory
7183
* @param HelperData $helperData
72-
* @param Filesystem $filesystem
84+
* @param Filesystem|null $filesystem
85+
* @param AddressMetadataInterface|null $addressMetadata
86+
* @param FileNameValidator|null $fileNameValidator
7387
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
7488
*/
7589
public function __construct(
@@ -86,11 +100,17 @@ public function __construct(
86100
PageFactory $resultPageFactory,
87101
RegionFactory $regionFactory,
88102
HelperData $helperData,
89-
?Filesystem $filesystem = null
103+
?Filesystem $filesystem = null,
104+
?AddressMetadataInterface $addressMetadata = null,
105+
?FileNameValidator $fileNameValidator = null
90106
) {
91107
$this->regionFactory = $regionFactory;
92108
$this->helperData = $helperData;
93109
$this->filesystem = $filesystem ?: ObjectManager::getInstance()->get(Filesystem::class);
110+
$this->addressMetadata = $addressMetadata
111+
?: ObjectManager::getInstance()->get(AddressMetadataInterface::class);
112+
$this->fileNameValidator = $fileNameValidator
113+
?: ObjectManager::getInstance()->get(FileNameValidator::class);
94114
parent::__construct(
95115
$context,
96116
$customerSession,
@@ -253,6 +273,7 @@ public function execute()
253273
* @return Mapper
254274
*
255275
* @deprecated 100.1.3
276+
* @see Mapper
256277
*/
257278
private function getCustomerAddressMapper()
258279
{
@@ -272,19 +293,33 @@ private function getCustomerAddressMapper()
272293
*/
273294
private function deleteAddressFileAttribute($address)
274295
{
275-
$attributeValue = $address->getCustomAttribute($this->_request->getParam('delete_attribute_value'));
276-
if ($attributeValue!== null) {
277-
if ($attributeValue->getValue() !== '') {
296+
$attributeCode = $this->_request->getParam('delete_attribute_value');
297+
$attributeValue = $address->getCustomAttribute($attributeCode);
298+
299+
if ($attributeValue !== null) {
300+
$attributeMetadata = $this->addressMetadata->getAttributeMetadata($attributeCode);
301+
302+
if ($attributeMetadata &&
303+
$attributeMetadata->getFrontendInput() === 'file' &&
304+
$attributeValue->getValue() !== ''
305+
) {
278306
$mediaDirectory = $this->filesystem->getDirectoryWrite(DirectoryList::MEDIA);
279307
$fileName = $attributeValue->getValue();
280-
$path = $mediaDirectory->getAbsolutePath('customer_address' . $fileName);
281-
if ($fileName && $mediaDirectory->isFile($path)) {
282-
$mediaDirectory->delete($path);
308+
309+
$filePath = AddressMetadataInterface::ENTITY_TYPE_ADDRESS
310+
. DIRECTORY_SEPARATOR
311+
. ltrim($fileName, DIRECTORY_SEPARATOR);
312+
$absolutePath = $mediaDirectory->getAbsolutePath($filePath);
313+
$allowedAbsolutePath = $mediaDirectory->getAbsolutePath(AddressMetadataInterface::ENTITY_TYPE_ADDRESS);
314+
315+
// Validate the file path
316+
$this->fileNameValidator->validate($fileName, $absolutePath, $allowedAbsolutePath);
317+
318+
if ($fileName && $mediaDirectory->isFile($filePath)) {
319+
$mediaDirectory->delete($filePath);
283320
}
284-
$address->setCustomAttribute(
285-
$this->_request->getParam('delete_attribute_value'),
286-
''
287-
);
321+
322+
$address->setCustomAttribute($attributeCode, '');
288323
}
289324
}
290325

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
<?php
2+
/**
3+
* Copyright 2025 Adobe
4+
* All Rights Reserved.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\Customer\Model\Validator\Address;
9+
10+
use Magento\Framework\Exception\LocalizedException;
11+
use Magento\Framework\Filesystem\Driver\File as FileDriver;
12+
13+
/**
14+
* Validator for file uploads.
15+
*/
16+
class File
17+
{
18+
/**
19+
* Regular expression pattern for validating file paths.
20+
*/
21+
private const PATTERN_NAME = '/(?:^|\/|\\\\)('
22+
. '(?:\.{2}[\/\\\\]|%2e%2e%2f|%2e%2e\/|\.\.%2f|%2e%2e%5c|%2e%2e\\|\.\.%5c|'
23+
. '%252e%252e%255c|\.\.%255c|%2e%2e\\\\|\.\.\\\\|\.\.%5c|%c0%2e%2e%2f|%c0%2e%2e%5c|'
24+
. '%c0%ae%c0%ae%2f|%c0%ae%c0%ae%5c|%e0%40%ae%2e%2f|%e0%40%ae%2e%5c|%c0%2e%c0%2e%2f|'
25+
. '%c0%2e%c0%2e%5c)'
26+
. ')/';
27+
28+
/**
29+
* @var FileDriver
30+
*/
31+
private $fileDriver;
32+
33+
/**
34+
* @param FileDriver $fileDriver
35+
*/
36+
public function __construct(FileDriver $fileDriver)
37+
{
38+
$this->fileDriver = $fileDriver;
39+
}
40+
41+
/**
42+
* Validate the filename and path
43+
*
44+
* @param string $fileName
45+
* @param string $absolutePath
46+
* @param string $allowedAbsolutePath
47+
* @return void
48+
* @throws LocalizedException
49+
*/
50+
public function validate(string $fileName, string $absolutePath, string $allowedAbsolutePath): void
51+
{
52+
if (!$this->isValid($fileName) || !$this->isWithinAllowedDirectory($absolutePath, $allowedAbsolutePath)) {
53+
throw new LocalizedException(__('Invalid file path.'));
54+
}
55+
}
56+
57+
/**
58+
* Check if the filename is valid
59+
*
60+
* @param string $fileName
61+
* @return bool
62+
*/
63+
private function isValid(string $fileName): bool
64+
{
65+
return !preg_match(self::PATTERN_NAME, $fileName);
66+
}
67+
68+
/**
69+
* Check if the path is within the allowed directory
70+
*
71+
* @param string $absolutePath
72+
* @param string $allowedAbsolutePath
73+
* @return bool
74+
*/
75+
private function isWithinAllowedDirectory(string $absolutePath, string $allowedAbsolutePath): bool
76+
{
77+
$absolutePath = $this->fileDriver->getRealPath($absolutePath);
78+
$allowedAbsolutePath = $this->fileDriver->getRealPath($allowedAbsolutePath);
79+
return strpos($absolutePath, $allowedAbsolutePath) === 0;
80+
}
81+
}

0 commit comments

Comments
 (0)