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
2
Answers
If there is no way to pass GDFONTPATH via Apache config, then this is the workaround solution I'm using.
NOTE: This is based on the example code here.
Differences from the php.net example code:
$font = 'arial.ttf';
but that didn't work on Debian and I suspect only really works on Windows. However, if the example used a font-stack, it could've listed multiple fonts/relative-paths, and that's what I'm doing in my example.$font
with an absolute file-path. Otherwise, it'll leave$font
as it was.This pretty much does what I want, but if SetEnv worked as I expected, this additional code wouldn't be required!
NOTE: I only test for the
.ttf
file extension whereas the libgd code tries.ttf
,.pfa
,.pfb
, and.dfont
extensions.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.
Tested against:
GDFONTPATH References: