Page MenuHomePhorge

PHP 8.0 without GD installed: Unhandled Exception setting a project profile image: Call to undefined function imagecreatefromstring()
Closed, ResolvedPublic

Description

Steps to reproduce:

  1. PHP 8.1.8 without GD installed
  2. Create a project
  3. Go to http://phorge.localhost/project/manage/1/
  4. Select Edit Picture in the sidebar on the right to go to the Edit Project Picture at http://phorge.localhost/project/picture/1/
  5. On Custom: Choose Icon and Color..., Choose Background Color and Choose Icon, then click the Save Image button.

Actual outcome:

[2023-05-01 22:25:09] EXCEPTION: (Error) Call to undefined function imagecreatefromstring() at [<phorge>/src/applications/files/builtin/PhabricatorFilesComposeIconBuiltinFile.php:131]
arcanist(head=T15263, ref.master=82d1abd4edd1, ref.T15263=4324d11c8b49), phorge(head=master, ref.master=8f669ea08289)
  #0 phlog(Error) called at [<phorge>/src/aphront/handler/PhabricatorDefaultRequestExceptionHandler.php:41]
  #1 PhabricatorDefaultRequestExceptionHandler::handleRequestThrowable(AphrontRequest, Error) called at [<phorge>/src/aphront/configuration/AphrontApplicationConfiguration.php:751]
  #2 AphrontApplicationConfiguration::handleThrowable(Error) called at [<phorge>/src/aphront/configuration/AphrontApplicationConfiguration.php:296]
  #3 AphrontApplicationConfiguration::processRequest(AphrontRequest, PhutilDeferredLog, AphrontPHPHTTPSink, MultimeterControl) called at [<phorge>/src/aphront/configuration/AphrontApplicationConfiguration.php:204]
  #4 AphrontApplicationConfiguration::runHTTPRequest(AphrontPHPHTTPSink) called at [<phorge>/webroot/index.php:35]

Expected outcome:
Either a friendlier error message explaining what to do.
Or no error message at all.

Other comments:
Since PHP 8.0.0, PHP's imagecreatefromstring() "returns a GDImage instance on success; previously, a resource was returned."
Thus there is a currently undocumented requirement to have the PHP GD extension installed: https://www.php.net/manual/en/image.installation.php

I can confirm that installing php-gd-8.1.18 fixes the problem.

Event Timeline

aklapper renamed this task from PHP 8.0 without GD installed: Unhandled Exception setting a project profile image to PHP 8.0 without GD installed: Unhandled Exception setting a project profile image: Call to undefined function imagecreatefromstring().May 1 2023, 22:35

Pseudo code, not tested as other exceptions block me from testing:

diff --git a/src/applications/config/check/PhabricatorPHPPreflightSetupCheck.php b/src/applications/config/check/PhabricatorPHPPreflightSetupCheck.php
index 02c1134dc3..adb8cafd8d 100644
--- a/src/applications/config/check/PhabricatorPHPPreflightSetupCheck.php
+++ b/src/applications/config/check/PhabricatorPHPPreflightSetupCheck.php
@@ -146,5 +146,22 @@ final class PhabricatorPHPPreflightSetupCheck extends PhabricatorSetupCheck {
         ->setMessage($message);
     }
 
+    if (version_compare($version, 8, '>=') && !extension_loaded('gd')) {
+      $message = pht(
+        "The PHP GD extension is not installed. GD is required for processing ".
+        "image files, such as user profile or project profile pictures.".
+        "\n\n".
+        "Please install the PHP GD extension.");
+
+      $this->newIssue('php.gd')
+        ->setIsFatal(true)
+        ->setName(pht('PHP GD Extension Not Installed'))
+        ->setMessage($message)
+        ->addLink(
+          'https://www.php.net/manual/image.installation.php',
+          pht('Install GD Support in PHP'));
+      return;
+    }
+
   }
 }

I just realized that src/applications/config/check/PhabricatorGDSetupCheck.php exists. Thus please ignore my last comment. Still, things should fail gracefully instead of showing an exception.

Also, trying to Upload Picture in a user Profile, not having php-gd installed leads to a confusing error message not listing any file formats:
This server only supports these image formats: .

Do you mean PHP 8.0 or PHP 8.1? I'm confused.

Do you mean PHP 8.0 or PHP 8.1? I'm confused.

Since PHP 8.0.0, PHP's imagecreatefromstring() "returns a GDImage instance on success; previously, a resource was returned."