Issue
Short Question
I want to pass GDFONTPATH environment variable from Apache vhost.conf to PHP. How can I do this?
I am running: Debian 12, Apache 2.4, PHP 8.2
Long question
I am using GD image functions (e.g. imagettftext
) in PHP and want to use specific fonts that may not be available system wide. This can be done by setting the environment variable GDFONTPATH
and the PHP function putenv
is good for this purpose.
However, putenv
is also a security concern, and as such on my production servers, I have it listed on disable_functions
in my php.ini
and as a result, I can't set this environment var within my PHP script. Instead, setting it using SetEnv
in my Apache vhost .conf file seems like a good idea (this is a cut-down example):
<Directory "/srv/www/example.com/public">
AllowOverride None
Require all granted
SetEnv GDFONTPATH "/srv/www/example.com/private/fonts"
</Directory>
The snag is, this doesn't work as [I] expected! It does set GDFONTPATH, but not locally, so I get the following results:
getenv('GDFONTPATH'); # Returns '/srv/www/example.com/private/fonts'
getenv('GDFONTPATH', true); # Returns ''
The libgd functions ignore this; they only look at the local environment variable that I only seem to be able to set using the putenv
function. But enabling putenv
on my production servers is not practical for security reasons, hence my really wanting to use SetEnv
in my Apache config!
FWIW: I've coded a "pragmatic" work-around that will use PHP's getenv
to read the path from Apache's SetEnv
, and then pass a fully-qualified font-filename to gdlib. This works, but is less than ideal! I'll likely post this code for future reference, but I really would like a solution where I can set the environment from Apache. This post might offer a potential solution, but it looks like it would apply to all vhosts, so again, not ideal.
I'm a bit sketchy on the difference between environment variables and "local" environment variables.
References: libgd source regarding GDFONTPATH
Solution
SetEnv GDFONTPATH "..."
As you've already found out, SetEnv GDFONTPATH "..."
sets Apache HTTPD internal variables, accessible through PHPs' SAPI via getenv() but not getenv(..., true) for system environment variables. Simply spoken, PHP getenv()s' $local = true variables aren't Apache internal environment variables.
GDFONTPATH
The GDFONTPATH system environment variable is in use by gdlib as the font-search-path parameter, that is similar to PATH, but for font files, not executable files.
This makes sense, e.g. to get access to fonts configured with the system, this is similar as to execute binaries on that system: Specifying the basename only suffices.
However, when your intend is to use a font file that is not configured on that system, again similar as with binaries, you need to provide the absolute pathname of the font that resolves to the directory entry of type file for that font, readable by the user the PHP process is running under. [credentials(7)]
$font_dirname = '/srv/www/example.com/private/fonts';
$font_basename = 'example.ttf';
$font_filename = $font_dirname . '/' . $font_basename;
set_error_handler(fn (int $type, string $message, string $file = null, int $line = null)
=> throw new ErrorException($message, 0, $type, $file, $line),
E_ALL,
);
imagettftext($image, $size, $angle, $x, $y, $color, $font_filename, $text);
restore_error_handler();
Tested against:
- PHP 8.2
- GD library 2.3.3
- GDFONTPATH unset
GDFONTPATH References:
- https://www.php.net/manual/en/function.imagefttext.php#refsect1-function.imagefttext-parameters
- https://github.com/libgd/libgd/blob/0d75136bd3e8651ded7c64a140791ed10de1c63c/src/gdft.c#L1789
Answered By - hakre Answer Checked By - Pedro (WPSolving Volunteer)