Skip to content

Commit 6e5fa6f

Browse files
authored
IBX-7485: Skipped files with corrupted filenames when loading and deleting content
For more details see https://issues.ibexa.co/browse/IBX-7485 and #400 Key changes: * Skipped files with corrupted filenames when loading and deleting * [Tests] Added integration test
1 parent 29489e4 commit 6e5fa6f

File tree

3 files changed

+114
-3
lines changed

3 files changed

+114
-3
lines changed

eZ/Publish/API/Repository/Tests/FieldType/ImageIntegrationTest.php

+105
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,12 @@
66
*/
77
namespace eZ\Publish\API\Repository\Tests\FieldType;
88

9+
use Doctrine\DBAL\ParameterType;
10+
use DOMDocument;
911
use eZ\Publish\API\Repository\Values\Content\Content;
1012
use eZ\Publish\API\Repository\Values\Content\Field;
1113
use eZ\Publish\Core\FieldType\Image\Value as ImageValue;
14+
use eZ\Publish\Core\Persistence\Legacy\Content\Gateway;
1215

1316
/**
1417
* Integration test for use field type.
@@ -760,6 +763,108 @@ public function testRemovingDraftRemovesOldImage(): void
760763
);
761764
}
762765

766+
public function testDeleteImageWithCorruptedName(): void
767+
{
768+
$content = $this->publishNewImage(
769+
__METHOD__,
770+
new ImageValue(
771+
[
772+
'inputUri' => __DIR__ . '/_fixtures/image.jpg',
773+
'fileName' => 'image.jpg',
774+
'fileSize' => filesize(__DIR__ . '/_fixtures/image.jpg'),
775+
'alternativeText' => 'Alternative',
776+
]
777+
),
778+
[2]
779+
);
780+
781+
$imageFieldDefinition = $content->getContentType()->getFieldDefinition('image');
782+
783+
$record = $this->fetchXML(
784+
$content->id,
785+
$content->getVersionInfo()->versionNo,
786+
$imageFieldDefinition->id
787+
);
788+
789+
$document = $this->corruptImageFieldXML($record);
790+
791+
$this->updateXML(
792+
$content->id,
793+
$content->getVersionInfo()->versionNo,
794+
$imageFieldDefinition->id,
795+
$document
796+
);
797+
798+
$repository = $this->getRepository(false);
799+
$contentService = $repository->getContentService();
800+
801+
$contentService->deleteContent($content->getVersionInfo()->getContentInfo());
802+
803+
// Expect no League\Flysystem\CorruptedPathDetected thrown
804+
}
805+
806+
/**
807+
* @return array<string,mixed>
808+
*/
809+
private function fetchXML(int $contentId, int $versionNo, int $fieldDefinitionId): array
810+
{
811+
$connection = $this->getRawDatabaseConnection();
812+
813+
$query = $connection->createQueryBuilder();
814+
$query
815+
->select('data_text')
816+
->from(Gateway::CONTENT_FIELD_TABLE)
817+
->andWhere('contentclassattribute_id = :contentclassattribute_id')
818+
->andWhere('version = :version')
819+
->andWhere('contentobject_id = :contentobject_id')
820+
->setParameter('contentclassattribute_id', $fieldDefinitionId, ParameterType::INTEGER)
821+
->setParameter('version', $versionNo, ParameterType::INTEGER)
822+
->setParameter('contentobject_id', $contentId, ParameterType::INTEGER);
823+
$result = $query->execute();
824+
825+
return $result->fetchAssociative();
826+
}
827+
828+
/**
829+
* @param array<string,mixed> $row
830+
*/
831+
private function corruptImageFieldXML(array $row): DOMDocument
832+
{
833+
$corruptedChar = '­';
834+
835+
$document = new DOMDocument('1.0', 'utf-8');
836+
$document->loadXML($row['data_text']);
837+
$elements = $document->getElementsByTagName('ezimage');
838+
$element = $elements->item(0);
839+
$element->setAttribute('filename', $element->getAttribute('filename') . $corruptedChar);
840+
$element->setAttribute('url', $element->getAttribute('url') . $corruptedChar);
841+
842+
return $document;
843+
}
844+
845+
private function updateXML(
846+
int $contentId,
847+
int $versionNo,
848+
int $fieldDefinitionId,
849+
DOMDocument $document
850+
): void {
851+
$connection = $this->getRawDatabaseConnection();
852+
853+
$query = $connection->createQueryBuilder();
854+
$query
855+
->update(Gateway::CONTENT_FIELD_TABLE)
856+
->set('data_text', ':data_text')
857+
->setParameter('data_text', $document->saveXML(), ParameterType::STRING)
858+
->andWhere('contentclassattribute_id = :contentclassattribute_id')
859+
->andWhere('version = :version')
860+
->andWhere('contentobject_id = :contentobject_id')
861+
->setParameter('contentclassattribute_id', $fieldDefinitionId, ParameterType::INTEGER)
862+
->setParameter('version', $versionNo, ParameterType::INTEGER)
863+
->setParameter('contentobject_id', $contentId, ParameterType::INTEGER);
864+
865+
$query->execute();
866+
}
867+
763868
/**
764869
* @throws \eZ\Publish\API\Repository\Exceptions\ForbiddenException
765870
* @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException

eZ/Publish/Core/IO/IOBinarydataHandler/Flysystem.php

+2-1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
use eZ\Publish\Core\IO\UrlDecorator;
1212
use eZ\Publish\SPI\IO\BinaryFileCreateStruct;
1313
use League\Flysystem\AdapterInterface;
14+
use League\Flysystem\CorruptedPathDetected;
1415
use League\Flysystem\FileExistsException;
1516
use League\Flysystem\FileNotFoundException as FlysystemNotFoundException;
1617
use League\Flysystem\FilesystemInterface;
@@ -56,7 +57,7 @@ public function delete($spiBinaryFileId)
5657
{
5758
try {
5859
$this->filesystem->delete($spiBinaryFileId);
59-
} catch (FlysystemNotFoundException $e) {
60+
} catch (FlysystemNotFoundException|CorruptedPathDetected $e) {
6061
throw new BinaryFileNotFoundException($spiBinaryFileId, $e);
6162
}
6263
}

eZ/Publish/Core/IO/IOMetadataHandler/Flysystem.php

+7-2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
use eZ\Publish\Core\IO\IOMetadataHandler;
1212
use eZ\Publish\SPI\IO\BinaryFile as SPIBinaryFile;
1313
use eZ\Publish\SPI\IO\BinaryFileCreateStruct as SPIBinaryFileCreateStruct;
14+
use League\Flysystem\CorruptedPathDetected;
1415
use League\Flysystem\FileNotFoundException;
1516
use League\Flysystem\FilesystemInterface;
1617

@@ -47,7 +48,7 @@ public function load($spiBinaryFileId)
4748
{
4849
try {
4950
$info = $this->filesystem->getMetadata($spiBinaryFileId);
50-
} catch (FileNotFoundException $e) {
51+
} catch (FileNotFoundException|CorruptedPathDetected $e) {
5152
throw new BinaryFileNotFoundException($spiBinaryFileId);
5253
}
5354

@@ -64,7 +65,11 @@ public function load($spiBinaryFileId)
6465

6566
public function exists($spiBinaryFileId)
6667
{
67-
return $this->filesystem->has($spiBinaryFileId);
68+
try {
69+
return $this->filesystem->has($spiBinaryFileId);
70+
} catch (CorruptedPathDetected $e) {
71+
return false;
72+
}
6873
}
6974

7075
public function getMimeType($spiBinaryFileId)

0 commit comments

Comments
 (0)