Merge pull request #29479 from nextcloud/fix/images-php-8.0

Fix image handling for PHP 8.0
pull/29527/head
Côme Chilliet 2021-11-02 10:57:08 +07:00 committed by GitHub
commit f90176efce
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 30 additions and 111 deletions

@ -122,7 +122,7 @@ class UserAvatar extends Avatar {
/** /**
* Returns an image from several sources. * Returns an image from several sources.
* *
* @param IImage|resource|string $data An image object, imagedata or path to the avatar * @param IImage|resource|string|\GdImage $data An image object, imagedata or path to the avatar
* @return IImage * @return IImage
*/ */
private function getAvatarImage($data) { private function getAvatarImage($data) {
@ -131,7 +131,10 @@ class UserAvatar extends Avatar {
} }
$img = new OC_Image(); $img = new OC_Image();
if (is_resource($data) && get_resource_type($data) === 'gd') { if (
(is_resource($data) && get_resource_type($data) === 'gd') ||
(is_object($data) && get_class($data) === \GdImage::class)
) {
$img->setResource($data); $img->setResource($data);
} elseif (is_resource($data)) { } elseif (is_resource($data)) {
$img->loadFromFileHandle($data); $img->loadFromFileHandle($data);

@ -60,7 +60,7 @@ abstract class Bitmap extends ProviderV2 {
//new bitmap image object //new bitmap image object
$image = new \OC_Image(); $image = new \OC_Image();
$image->loadFromData($bp); $image->loadFromData((string) $bp);
//check if image object is valid //check if image object is valid
return $image->valid() ? $image : null; return $image->valid() ? $image : null;
} }

@ -81,7 +81,7 @@ class HEIC extends ProviderV2 {
//new bitmap image object //new bitmap image object
$image = new \OC_Image(); $image = new \OC_Image();
$image->loadFromData($bp); $image->loadFromData((string) $bp);
//check if image object is valid //check if image object is valid
return $image->valid() ? $image : null; return $image->valid() ? $image : null;
} }

@ -69,7 +69,7 @@ class SVG extends ProviderV2 {
//new image object //new image object
$image = new \OC_Image(); $image = new \OC_Image();
$image->loadFromData($svg); $image->loadFromData((string) $svg);
//check if image object is valid //check if image object is valid
if ($image->valid()) { if ($image->valid()) {
$image->scaleDownToFit($maxX, $maxY); $image->scaleDownToFit($maxX, $maxY);

@ -101,7 +101,7 @@ class OC_Image implements \OCP\IImage {
if (is_resource($this->resource)) { if (is_resource($this->resource)) {
return true; return true;
} }
if (is_object($this->resource) && get_class($this->resource) === 'GdImage') { if (is_object($this->resource) && get_class($this->resource) === \GdImage::class) {
return true; return true;
} }
@ -308,7 +308,7 @@ class OC_Image implements \OCP\IImage {
} }
/** /**
* @param resource Returns the image resource in any. * @param resource|\GdImage $resource
* @throws \InvalidArgumentException in case the supplied resource does not have the type "gd" * @throws \InvalidArgumentException in case the supplied resource does not have the type "gd"
*/ */
public function setResource($resource) { public function setResource($resource) {
@ -318,7 +318,7 @@ class OC_Image implements \OCP\IImage {
return; return;
} }
// PHP 8 has real objects for GD stuff // PHP 8 has real objects for GD stuff
if (is_object($resource) && get_class($resource) === 'GdImage') { if (is_object($resource) && get_class($resource) === \GdImage::class) {
$this->resource = $resource; $this->resource = $resource;
return; return;
} }
@ -326,7 +326,7 @@ class OC_Image implements \OCP\IImage {
} }
/** /**
* @return resource Returns the image resource in any. * @return resource|\GdImage Returns the image resource in any.
*/ */
public function resource() { public function resource() {
return $this->resource; return $this->resource;
@ -536,7 +536,7 @@ class OC_Image implements \OCP\IImage {
* It is the responsibility of the caller to position the pointer at the correct place and to close the handle again. * It is the responsibility of the caller to position the pointer at the correct place and to close the handle again.
* *
* @param resource $handle * @param resource $handle
* @return resource|false An image resource or false on error * @return resource|\GdImage|false An image resource or false on error
*/ */
public function loadFromFileHandle($handle) { public function loadFromFileHandle($handle) {
$contents = stream_get_contents($handle); $contents = stream_get_contents($handle);
@ -550,7 +550,7 @@ class OC_Image implements \OCP\IImage {
* Loads an image from a local file. * Loads an image from a local file.
* *
* @param bool|string $imagePath The path to a local file. * @param bool|string $imagePath The path to a local file.
* @return bool|resource An image resource or false on error * @return bool|resource|\GdImage An image resource or false on error
*/ */
public function loadFromFile($imagePath = false) { public function loadFromFile($imagePath = false) {
// exif_imagetype throws "read error!" if file is less than 12 byte // exif_imagetype throws "read error!" if file is less than 12 byte
@ -666,17 +666,17 @@ class OC_Image implements \OCP\IImage {
* Loads an image from a string of data. * Loads an image from a string of data.
* *
* @param string $str A string of image data as read from a file. * @param string $str A string of image data as read from a file.
* @return bool|resource An image resource or false on error * @return bool|resource|\GdImage An image resource or false on error
*/ */
public function loadFromData($str) { public function loadFromData($str) {
if (is_resource($str)) { if (!is_string($str)) {
return false; return false;
} }
$this->resource = @imagecreatefromstring($str); $this->resource = @imagecreatefromstring($str);
if ($this->fileInfo) { if ($this->fileInfo) {
$this->mimeType = $this->fileInfo->buffer($str); $this->mimeType = $this->fileInfo->buffer($str);
} }
if (is_resource($this->resource)) { if ($this->valid()) {
imagealphablending($this->resource, false); imagealphablending($this->resource, false);
imagesavealpha($this->resource, true); imagesavealpha($this->resource, true);
} }
@ -692,7 +692,7 @@ class OC_Image implements \OCP\IImage {
* Loads an image from a base64 encoded string. * Loads an image from a base64 encoded string.
* *
* @param string $str A string base64 encoded string of image data. * @param string $str A string base64 encoded string of image data.
* @return bool|resource An image resource or false on error * @return bool|resource|\GdImage An image resource or false on error
*/ */
public function loadFromBase64($str) { public function loadFromBase64($str) {
if (!is_string($str)) { if (!is_string($str)) {
@ -722,7 +722,7 @@ class OC_Image implements \OCP\IImage {
* @param string $fileName <p> * @param string $fileName <p>
* Path to the BMP image. * Path to the BMP image.
* </p> * </p>
* @return bool|resource an image resource identifier on success, <b>FALSE</b> on errors. * @return bool|resource|\GdImage an image resource identifier on success, <b>FALSE</b> on errors.
*/ */
private function imagecreatefrombmp($fileName) { private function imagecreatefrombmp($fileName) {
if (!($fh = fopen($fileName, 'rb'))) { if (!($fh = fopen($fileName, 'rb'))) {
@ -878,12 +878,12 @@ class OC_Image implements \OCP\IImage {
$result = $this->resizeNew($maxSize); $result = $this->resizeNew($maxSize);
imagedestroy($this->resource); imagedestroy($this->resource);
$this->resource = $result; $this->resource = $result;
return is_resource($result); return $this->valid();
} }
/** /**
* @param $maxSize * @param $maxSize
* @return resource | bool * @return resource|bool|\GdImage
*/ */
private function resizeNew($maxSize) { private function resizeNew($maxSize) {
if (!$this->valid()) { if (!$this->valid()) {
@ -914,14 +914,14 @@ class OC_Image implements \OCP\IImage {
$result = $this->preciseResizeNew($width, $height); $result = $this->preciseResizeNew($width, $height);
imagedestroy($this->resource); imagedestroy($this->resource);
$this->resource = $result; $this->resource = $result;
return is_resource($result); return $this->valid();
} }
/** /**
* @param int $width * @param int $width
* @param int $height * @param int $height
* @return resource | bool * @return resource|bool|\GdImage
*/ */
public function preciseResizeNew(int $width, int $height) { public function preciseResizeNew(int $width, int $height) {
if (!$this->valid()) { if (!$this->valid()) {
@ -1023,7 +1023,7 @@ class OC_Image implements \OCP\IImage {
$result = $this->cropNew($x, $y, $w, $h); $result = $this->cropNew($x, $y, $w, $h);
imagedestroy($this->resource); imagedestroy($this->resource);
$this->resource = $result; $this->resource = $result;
return is_resource($result); return $this->valid();
} }
/** /**
@ -1181,7 +1181,7 @@ if (!function_exists('imagebmp')) {
* @link http://www.programmierer-forum.de/imagebmp-gute-funktion-gefunden-t143716.htm * @link http://www.programmierer-forum.de/imagebmp-gute-funktion-gefunden-t143716.htm
* @author mgutt <marc@gutt.it> * @author mgutt <marc@gutt.it>
* @version 1.00 * @version 1.00
* @param resource $im * @param resource|\GdImage $im
* @param string $fileName [optional] <p>The path to save the file to.</p> * @param string $fileName [optional] <p>The path to save the file to.</p>
* @param int $bit [optional] <p>Bit depth, (default is 24).</p> * @param int $bit [optional] <p>Bit depth, (default is 24).</p>
* @param int $compression [optional] * @param int $compression [optional]

@ -98,7 +98,7 @@ interface IImage {
public function save($filePath = null, $mimeType = null); public function save($filePath = null, $mimeType = null);
/** /**
* @return resource Returns the image resource in any. * @return resource|\GdImage Returns the image resource in any.
* @since 8.1.0 * @since 8.1.0
*/ */
public function resource(); public function resource();

@ -81,6 +81,8 @@
<errorLevel type="suppress"> <errorLevel type="suppress">
<referencedClass name="OCA\GroupFolders\Mount\GroupFolderStorage"/> <referencedClass name="OCA\GroupFolders\Mount\GroupFolderStorage"/>
<referencedClass name="OCA\TwoFactorNextcloudNotification\Controller\APIController"/> <referencedClass name="OCA\TwoFactorNextcloudNotification\Controller\APIController"/>
<!-- Classes from PHP>=8 (needed to be able to use \GdImage::class) -->
<referencedClass name="GdImage" />
</errorLevel> </errorLevel>
</UndefinedClass> </UndefinedClass>
<UndefinedFunction> <UndefinedFunction>
@ -124,6 +126,8 @@
<!-- Helper classes for sharing API integration from other apps --> <!-- Helper classes for sharing API integration from other apps -->
<referencedClass name="OCA\Deck\Sharing\ShareAPIHelper" /> <referencedClass name="OCA\Deck\Sharing\ShareAPIHelper" />
<referencedClass name="OCA\Talk\Share\Helper\DeletedShareAPIController" /> <referencedClass name="OCA\Talk\Share\Helper\DeletedShareAPIController" />
<!-- Classes from PHP>=8 -->
<referencedClass name="GdImage" />
</errorLevel> </errorLevel>
</UndefinedDocblockClass> </UndefinedDocblockClass>
</issueHandlers> </issueHandlers>

@ -52,10 +52,6 @@ class UserAvatarTest extends \Test\TestCase {
} }
public function testGetNoAvatar() { public function testGetNoAvatar() {
if (PHP_MAJOR_VERSION > 7) {
$this->markTestSkipped('Only run on php7');
}
$file = $this->createMock(ISimpleFile::class); $file = $this->createMock(ISimpleFile::class);
$this->folder->method('newFile') $this->folder->method('newFile')
->willReturn($file); ->willReturn($file);
@ -91,10 +87,6 @@ class UserAvatarTest extends \Test\TestCase {
} }
public function testGetAvatarSizeMatch() { public function testGetAvatarSizeMatch() {
if (PHP_MAJOR_VERSION > 7) {
$this->markTestSkipped('Only run on php7');
}
$this->folder->method('fileExists') $this->folder->method('fileExists')
->willReturnMap([ ->willReturnMap([
['avatar.jpg', true], ['avatar.jpg', true],
@ -112,10 +104,6 @@ class UserAvatarTest extends \Test\TestCase {
} }
public function testGetAvatarSizeMinusOne() { public function testGetAvatarSizeMinusOne() {
if (PHP_MAJOR_VERSION > 7) {
$this->markTestSkipped('Only run on php7');
}
$this->folder->method('fileExists') $this->folder->method('fileExists')
->willReturnMap([ ->willReturnMap([
['avatar.jpg', true], ['avatar.jpg', true],
@ -132,10 +120,6 @@ class UserAvatarTest extends \Test\TestCase {
} }
public function testGetAvatarNoSizeMatch() { public function testGetAvatarNoSizeMatch() {
if (PHP_MAJOR_VERSION > 7) {
$this->markTestSkipped('Only run on php7');
}
$this->folder->method('fileExists') $this->folder->method('fileExists')
->willReturnMap([ ->willReturnMap([
['avatar.png', true], ['avatar.png', true],
@ -200,10 +184,6 @@ class UserAvatarTest extends \Test\TestCase {
} }
public function testSetAvatar() { public function testSetAvatar() {
if (PHP_MAJOR_VERSION > 7) {
$this->markTestSkipped('Only run on php7');
}
$avatarFileJPG = $this->createMock(File::class); $avatarFileJPG = $this->createMock(File::class);
$avatarFileJPG->method('getName') $avatarFileJPG->method('getName')
->willReturn('avatar.jpg'); ->willReturn('avatar.jpg');

@ -20,10 +20,6 @@ class ImageTest extends \Test\TestCase {
} }
public function testConstructDestruct() { public function testConstructDestruct() {
if (PHP_MAJOR_VERSION > 7) {
$this->markTestSkipped('Only run on php7');
}
$img = new \OC_Image(); $img = new \OC_Image();
$img->loadFromFile(OC::$SERVERROOT.'/tests/data/testimage.png'); $img->loadFromFile(OC::$SERVERROOT.'/tests/data/testimage.png');
$this->assertInstanceOf('\OC_Image', $img); $this->assertInstanceOf('\OC_Image', $img);
@ -51,10 +47,6 @@ class ImageTest extends \Test\TestCase {
} }
public function testValid() { public function testValid() {
if (PHP_MAJOR_VERSION > 7) {
$this->markTestSkipped('Only run on php7');
}
$img = new \OC_Image(); $img = new \OC_Image();
$img->loadFromFile(OC::$SERVERROOT.'/tests/data/testimage.png'); $img->loadFromFile(OC::$SERVERROOT.'/tests/data/testimage.png');
$this->assertTrue($img->valid()); $this->assertTrue($img->valid());
@ -69,10 +61,6 @@ class ImageTest extends \Test\TestCase {
} }
public function testMimeType() { public function testMimeType() {
if (PHP_MAJOR_VERSION > 7) {
$this->markTestSkipped('Only run on php7');
}
$img = new \OC_Image(); $img = new \OC_Image();
$img->loadFromFile(OC::$SERVERROOT.'/tests/data/testimage.png'); $img->loadFromFile(OC::$SERVERROOT.'/tests/data/testimage.png');
$this->assertEquals('image/png', $img->mimeType()); $this->assertEquals('image/png', $img->mimeType());
@ -90,10 +78,6 @@ class ImageTest extends \Test\TestCase {
} }
public function testWidth() { public function testWidth() {
if (PHP_MAJOR_VERSION > 7) {
$this->markTestSkipped('Only run on php7');
}
$img = new \OC_Image(); $img = new \OC_Image();
$img->loadFromFile(OC::$SERVERROOT.'/tests/data/testimage.png'); $img->loadFromFile(OC::$SERVERROOT.'/tests/data/testimage.png');
$this->assertEquals(128, $img->width()); $this->assertEquals(128, $img->width());
@ -111,10 +95,6 @@ class ImageTest extends \Test\TestCase {
} }
public function testHeight() { public function testHeight() {
if (PHP_MAJOR_VERSION > 7) {
$this->markTestSkipped('Only run on php7');
}
$img = new \OC_Image(); $img = new \OC_Image();
$img->loadFromFile(OC::$SERVERROOT.'/tests/data/testimage.png'); $img->loadFromFile(OC::$SERVERROOT.'/tests/data/testimage.png');
$this->assertEquals(128, $img->height()); $this->assertEquals(128, $img->height());
@ -132,10 +112,6 @@ class ImageTest extends \Test\TestCase {
} }
public function testSave() { public function testSave() {
if (PHP_MAJOR_VERSION > 7) {
$this->markTestSkipped('Only run on php7');
}
$img = new \OC_Image(); $img = new \OC_Image();
$img->loadFromFile(OC::$SERVERROOT.'/tests/data/testimage.png'); $img->loadFromFile(OC::$SERVERROOT.'/tests/data/testimage.png');
$img->resize(16); $img->resize(16);
@ -150,10 +126,6 @@ class ImageTest extends \Test\TestCase {
} }
public function testData() { public function testData() {
if (PHP_MAJOR_VERSION > 7) {
$this->markTestSkipped('Only run on php7');
}
$img = new \OC_Image(); $img = new \OC_Image();
$img->loadFromFile(OC::$SERVERROOT.'/tests/data/testimage.png'); $img->loadFromFile(OC::$SERVERROOT.'/tests/data/testimage.png');
$raw = imagecreatefromstring(file_get_contents(OC::$SERVERROOT.'/tests/data/testimage.png')); $raw = imagecreatefromstring(file_get_contents(OC::$SERVERROOT.'/tests/data/testimage.png'));
@ -188,10 +160,6 @@ class ImageTest extends \Test\TestCase {
} }
public function testDataNoResource() { public function testDataNoResource() {
if (PHP_MAJOR_VERSION > 7) {
$this->markTestSkipped('Only run on php7');
}
$img = new \OC_Image(); $img = new \OC_Image();
$this->assertNull($img->data()); $this->assertNull($img->data());
} }
@ -200,10 +168,6 @@ class ImageTest extends \Test\TestCase {
* @depends testData * @depends testData
*/ */
public function testToString() { public function testToString() {
if (PHP_MAJOR_VERSION > 7) {
$this->markTestSkipped('Only run on php7');
}
$img = new \OC_Image(); $img = new \OC_Image();
$img->loadFromFile(OC::$SERVERROOT.'/tests/data/testimage.png'); $img->loadFromFile(OC::$SERVERROOT.'/tests/data/testimage.png');
$expected = base64_encode($img->data()); $expected = base64_encode($img->data());
@ -221,10 +185,6 @@ class ImageTest extends \Test\TestCase {
} }
public function testResize() { public function testResize() {
if (PHP_MAJOR_VERSION > 7) {
$this->markTestSkipped('Only run on php7');
}
$img = new \OC_Image(); $img = new \OC_Image();
$img->loadFromFile(OC::$SERVERROOT.'/tests/data/testimage.png'); $img->loadFromFile(OC::$SERVERROOT.'/tests/data/testimage.png');
$this->assertTrue($img->resize(32)); $this->assertTrue($img->resize(32));
@ -245,10 +205,6 @@ class ImageTest extends \Test\TestCase {
} }
public function testPreciseResize() { public function testPreciseResize() {
if (PHP_MAJOR_VERSION > 7) {
$this->markTestSkipped('Only run on php7');
}
$img = new \OC_Image(); $img = new \OC_Image();
$img->loadFromFile(OC::$SERVERROOT.'/tests/data/testimage.png'); $img->loadFromFile(OC::$SERVERROOT.'/tests/data/testimage.png');
$this->assertTrue($img->preciseResize(128, 512)); $this->assertTrue($img->preciseResize(128, 512));
@ -269,10 +225,6 @@ class ImageTest extends \Test\TestCase {
} }
public function testCenterCrop() { public function testCenterCrop() {
if (PHP_MAJOR_VERSION > 7) {
$this->markTestSkipped('Only run on php7');
}
$img = new \OC_Image(); $img = new \OC_Image();
$img->loadFromFile(OC::$SERVERROOT.'/tests/data/testimage.png'); $img->loadFromFile(OC::$SERVERROOT.'/tests/data/testimage.png');
$img->centerCrop(); $img->centerCrop();
@ -293,10 +245,6 @@ class ImageTest extends \Test\TestCase {
} }
public function testCrop() { public function testCrop() {
if (PHP_MAJOR_VERSION > 7) {
$this->markTestSkipped('Only run on php7');
}
$img = new \OC_Image(); $img = new \OC_Image();
$img->loadFromFile(OC::$SERVERROOT.'/tests/data/testimage.png'); $img->loadFromFile(OC::$SERVERROOT.'/tests/data/testimage.png');
$this->assertTrue($img->crop(0, 0, 50, 20)); $this->assertTrue($img->crop(0, 0, 50, 20));
@ -332,10 +280,6 @@ class ImageTest extends \Test\TestCase {
* @param int[] $expected * @param int[] $expected
*/ */
public function testFitIn($filename, $asked, $expected) { public function testFitIn($filename, $asked, $expected) {
if (PHP_MAJOR_VERSION > 7) {
$this->markTestSkipped('Only run on php7');
}
$img = new \OC_Image(); $img = new \OC_Image();
$img->loadFromFile(OC::$SERVERROOT . '/tests/data/' . $filename); $img->loadFromFile(OC::$SERVERROOT . '/tests/data/' . $filename);
$this->assertTrue($img->fitIn($asked[0], $asked[1])); $this->assertTrue($img->fitIn($asked[0], $asked[1]));
@ -359,10 +303,6 @@ class ImageTest extends \Test\TestCase {
* @param string $filename * @param string $filename
*/ */
public function testScaleDownToFitWhenSmallerAlready($filename) { public function testScaleDownToFitWhenSmallerAlready($filename) {
if (PHP_MAJOR_VERSION > 7) {
$this->markTestSkipped('Only run on php7');
}
$img = new \OC_Image(); $img = new \OC_Image();
$img->loadFromFile(OC::$SERVERROOT.'/tests/data/' . $filename); $img->loadFromFile(OC::$SERVERROOT.'/tests/data/' . $filename);
$currentWidth = $img->width(); $currentWidth = $img->width();
@ -396,10 +336,6 @@ class ImageTest extends \Test\TestCase {
* @param int[] $expected * @param int[] $expected
*/ */
public function testScaleDownWhenBigger($filename, $asked, $expected) { public function testScaleDownWhenBigger($filename, $asked, $expected) {
if (PHP_MAJOR_VERSION > 7) {
$this->markTestSkipped('Only run on php7');
}
$img = new \OC_Image(); $img = new \OC_Image();
$img->loadFromFile(OC::$SERVERROOT.'/tests/data/' . $filename); $img->loadFromFile(OC::$SERVERROOT.'/tests/data/' . $filename);
//$this->assertTrue($img->scaleDownToFit($asked[0], $asked[1])); //$this->assertTrue($img->scaleDownToFit($asked[0], $asked[1]));
@ -420,10 +356,6 @@ class ImageTest extends \Test\TestCase {
* @dataProvider convertDataProvider * @dataProvider convertDataProvider
*/ */
public function testConvert($mimeType) { public function testConvert($mimeType) {
if (PHP_MAJOR_VERSION > 7) {
$this->markTestSkipped('Only run on php7');
}
$img = new \OC_Image(); $img = new \OC_Image();
$img->loadFromFile(OC::$SERVERROOT.'/tests/data/testimage.png'); $img->loadFromFile(OC::$SERVERROOT.'/tests/data/testimage.png');
$tempFile = tempnam(sys_get_temp_dir(), 'img-test'); $tempFile = tempnam(sys_get_temp_dir(), 'img-test');