When you have verified the necessary preconditions as described in the previous
paragraphs it is time to install the library. The "installing" part is nothing more
than copying the files in the distribution to a place in the directory structure
where you script can find the library files. On a Unix system it is common to
install PHP libraries under "/usr/share/php/
". On a windows
system there is really no standard path for installing PHP libraries so you have to
decide your self.
The important thing here is that the path to the library is included in the PHP
search path, i.e. it is in one of the paths that PHP searches when it tries to
resolve a "require_once
" or "include
" statements.
Furthermore, the included examples and demo applications (included in the pro
version) assumes that the library is installed under the directory
"jpgraph/
".
As an example the following commands will install a specific version of the
library on a Unix server. If we assume that you have downloaded the library to the
"/tmp/
" directory and are already standing in this
directory the following commands will setup the library to be used
root:/tmp> tar xzf jpgraph-2.5.tar.gz root:/tmp> cp -r jpgraph-2.5 /usr/shar/php/ root:/tmp> ln -s /usr/shar/php/jpgraph-2.5 /usr/shar/php/jpgraph
The last line makes a symbolic link from "jpgraph" to the actual version of the library. This way you can try out different versions of the library without having to make any changes in your scripts. You just point out a different version of the library in the symbolic link.
To find the location of your php.ini
file
create and run a script with the single line <?php
phpinfo(); ?>
. The look at the output for a line saying
"php.ini file used" and you will see which
php.ini
file is used.
Setting the memory limits
In many default configuration the allowed memory for PHP is not enough for complex graph script since they (as many other image manipulation programs) can require a lot of memory. On a development server there should be at least 32MB memory allowed for the HTTP/PHP process. To verify this do the following
Open php.ini
for editing.
Locate the line saying
memory_limit = xx
where "xx" is some number. Now make sure that you have at least 32MB allowed by making sure the line reads
memory_limit = 32M
Note that fore very large images this might not be enough. Consider the following example.
Assume you need to create an 1200x1024 image in true color. Just the plain image in itself will require 1200x1020x4 bytes, which is roughly 4.7MB RAM during internal processing the library can need up to three times that amount of memory so this means that just for the image the library needs around of ~15MB of RAM. If we then take the memory needed to load PHP as well as the entire JpGraph library and dynamically execute and parse the library it can easily consume another ~15MB RAM. If the image is very complex and requires a huge number of objects to be created (a typical example is a large Gantt chart) it might be necessary to double the allowed memory to 64MB RAM.
Setting maximum allowed run time
By default many installations have very short maximum run time for the PHP scripts. Common figures are 10s. For normal interactive use involving plain text processing this is usually adequate. However, producing large and complex images might take considerable time (as do all images processing). For this reason the maximum time limit for PHP should be increased to a minimum of 20s (depending on the complexity of your images as well as any associated data processing it might be necessary to allow up to 30-40s).
The allowed running time is controlled by the php.ini
setting
max_execution_time = xx
where "xx" is some number. Recommended setting is therefore
max_execution_time = 30
Disabling output buffer
The next part of the php.ini
file that might need
changing is the output buffer. In short this should be disabled and we will
shortly explain why. To check this do the following
Open php.ini
for editing
Locate the line saying
output_buffering = xx
where "xx" is some number. Make sure that this line is commented out, i.e. it reads
; output_buffering = xx
This reason we want this to be commented out is that during development we want to be able to see the potential error messages produced by the library and having the output buffering enabled will actually prevent this. Fully understanding why this is the case is good first step into the added complexity of producing images with PHP compared with just outputting text. Understanding this requires us to understand a few basic principles about the HTTP protocol. Especially how MIME encodings of data works.
The following explanation is slightly simplified since a full description of the HTTP protocol would bring us a bit to far in this manual
A client (e.g. browser) requests data from the server by issuing a GET (or possible a POST) command to the server. This is what happens when you enter a URI i the address bar in the browser.
The server replies with a data stream (or an error if the requested data wasn't available). This data stream is prepended with header (MIME header) that tells the client (e.g. the browser) how to interpret the data that follows. The most common type (and the default type if no header is sent by a faulty server) is "text/html" . This tells the client to interpret the data as plain text with embedded HTML encoding.
When the data is to be interpreted as an image the header will
instead be one of the image headers, for example
"image/png"
or "image/jpeg"
. When
the client receives this header it will Interpret all the
following data as an image encoded in the indicated format.
The important thing to keep in mind here is that each server reply can have one and only one MIME type. This is the key to further understanding the specific issues with dynamic image generation. This explains why if a PHP script running on the server sends a header first indicating that the following data it sends should be interpreted by the client as an image it cannot send both image data and some text.
We are now in a position to explain how output buffering would make debugging more difficult.
Normally all output from a PHP script is sequentially, i.e. the header
must first be sent and then the data. If no header is sent or plain text is
sent without a header the client will interpret this as
"text/html"
. One purpose with "output_buffer" it to
circumvent this to allow a certain amount of output to be put in a buffer
for a while and later when some processing has determined what header should
be sent the data is prepended with the correct header and the rest of the
data is then sent.
What could now happen is the following (not unlikely scenario):
The scripts starts executing and the image starts to be build.
Your script has some minor issues which produces some warnings from PHP. These warning does not get sent directly back to the client (the browser) to allow you to act on these warnings instead they will be put into the output buffer. When later the scripts starts outputting the proper image header and the image data it gets added to the output buffer where your previous textual PHP warning already are stored.
Your client now receives the header that indicates that the following data should be interpreted as an image but since that image data is mixed with the textual warning messages it will fail to decode the data (since it is not proper image data) and will typical just show the image as a square with a red-cross (FireFox) or some message along the lines of "Cannot decode image". This is all depending on how a certain client handles a corrupt image.
The above scenario makes it impossible to debug your script since it will give no clue to what caused or where in your script these warnings were generated. The way to counteract this scenario is to disable output buffering. In this way the warning will be sent back to the client as soon as they are generated by PHP and will allow you to act on them.
Enabling adequate error checking
The final part of the php.ini
file that should be
adjusted (and this is not only for the JpGraph library) is the error level.
To ensure maximum interoperability of the developed scripts they should all
run completely silent no matter what error levels are set on the server.
This means that development of all scripts should always be done with
maximum error checking enabled. The JpGraph library can safely run
completely silent even when all error checking is enabled.
The error checking should therefore be specified as
error_reporting = E_ALL | E_STRICT
to enable the highest degree of PHP error checking
In addition to the above setting it is a good idea to also to makes sure that the following options are set
zend.ze1_compatibility_mode = Off
Zend engine 1 compatibility might cause problems with the library
implicit_flush = On
This can reduce the performance and shouldn't be used on a production server but will make all outputs sent back to the client as soon as possible and will aid in debugging.
allow_call_time_pass_reference = Off
This is just a general good idea since call time pass references is deprecated in PHP 5.0 and higher
display_errors = On
This makes sure all error are displayed
display_startup_errors = On
This makes sure that any initial errors thrown by PHP will be reported
Setting default timezone
Starting with PHP 5.2 a warning will now be generated unless a default
time zone is explicitly specified in php.ini
. To set
this find the line date.timezone
in the
[Date]
section and set this to valid zone. For example to
specify GMT+1 one could specify
date.timezone = Europe/Paris
Note: There should be no citation signs around the time zone.
In order to use the LED module (See LED bill boards) the PHP installation must
have multi-byte strings enabled so that the function
mb_strlen() is available. This is normally
enabled at compile time for PHP by specifying the options
--enable-mbstring --enable-mbregex
when configuring
the compile options.
In order to use the PDF417 barcode module (See Chapter 25. PDF417 (2D-Barcode)) it is necessary for the PHP
installation to support the function bcmod().
This is enabled when compiling PHP by making sure that the option
--enable-bcmath
is given when configuring PHP at
compile time.
Apart from the standard configuration described in Installing and configuring Font support and Adapting and customizing the installation there is only one important configuration that is specific for a development server and that is the localization setting for error messages.
As of version 3.0.0 there are three localization options
English error messages ("en")
German error messages ("de")
Production error messages ("prod"). This is not really a localization but a different set of error messages which does not give detailed error messages but a generic message suitable for a production server where the end user is not helped by detailed graph script errors. Instead a generic message is shown together with an error code that corresponds to the detailed error. ("prod")
In order to specify the error message localization the
following define in jpg-config.inc.php
must be set the
define('DEFAULT_ERR_LOCALE','en');
The possible options are
"en", English locale
"de", German locale
"prod", The production version of the error messages.
In addition to specifying the locale in the
jpg-config.inc.php
file it can also be
specified dynamically in each script by calling
1 | JpGraphError::SetErrLocale($aLocale); |
Apart from what is applicable to a development server as described in Configuring JpGraph/PHP on a development server the following changes should be considered in a production environment.
Setting the memory limits
The one thing to keep in mind here is that each active connection will spawn a unique PHP instance (HTTP process). This means that the memory limit set per PHP process can cause a very high memory demand on a busy server with many simultaneous connections. For this reason it is important that during system test (before going into production) the actual needed memory limit is determined.
For a busy server it is not uncommon to dimension it so it can handle 100 simultaneous connections. If the limit of r each PHP process is set to 32MB this means that the server needs at least ~3.2GB memory just to handle the PHP processes (if they are all using there maximum allowed memory).
Setting maximum allowed run time
The same principle applies to a the allowed run time. For a production server with high load and many simultaneous users it might be necessary to increase the maximum allowed execution time just to be sure no process is terminated due to it reaching its maximum allowed run time. When that happens the PHP process will be killed an no output sent back to the client (e.g. the browser).
Disabling output buffer
The output buffer should be disabled on the production server as well since enabling this will slow down the PHP and put a higher demand on the memory requirements.
Enabling adequate error checking
On a production server it is not a good idea to display all PHP error messages to the end user so the display of error messages should be disabled and the error messages should only be logged to a file.
On a production server it is also a good to idea to have the following settings:
display_errors = Off
This makes sure that now PHP errors are displayed
display_startup_errors = Off
This makes sure that any initial errors thrown by PHP is not displayed to the end user
log_errors = On
error_log = <name-of-log-file>
This makes sure all server PHP errors are logged to a specified file
On a production server it is best not to show detailed error messages to an end user. Instead it is better to have a generic error message that indicates a server problem and give an error code which can be decoded by looking it up in the table in Appendix H. Error messages Using a generic error message is achieved by setting the following define:
define('DEFAULT_ERR_LOCALE','prod');
As was mentioned before the library should be installed somewhere in the PHP include path. There are two ways of configuring the include path:
setting the include path in php.ini
include_path = <file-path>
adjusting the include path directly in the code by using the PHP
command php_ini_set()
at the top of the script
The library examples assume that the library is available under a directory
called "jpgraph/
" . This will allow the scripts to include
the library files by, for example, writing "include
" or
"require_once
" statements such as
require_once( 'jpgraph/jpgraph.php')
This section only discusses alias setting using the Apache HTTP server so this section can be skipped at first time reading the manual without loss of continuation.
More detailed information on the alias directive is also available in
the official Apache documentation at http://httpd.apache.org/docs/2.2/mod/mod_alias.html
When accessing examples and test code through a regular bowser during
development the scripts must be available in document root (or somewhere beneath
that root) the root is traditionally named /htdocs
. Having a
development code/repository directly under this root directory is not a good
idea. For example, write access to a document root (even on a development
server) should be restricted, in addition the paths given to a test team should
be the same whatever version is currently under test so storing different
versions with different names under the root is also a poor setup.
A much better and easy, approach is to use the powerful concept of alias in
Apache. This is a way of mapping a URL to a specific directory on the server.
For example if Eclipse-PDT
is used as an IDE to develop PHP it is mandatory to have a workspace setup where
all the working files resides. Assuming that a local developer has his workspace
directly in his home directory, say ~joe/workspace
, we
could configure an alias so that the workspace is accessible by the alias
"http://localhost/ws/
" by adding the following
configuration in the Apache setup file(s)
1 2 3 4 5 | Alias /ws /home/joe/worksapce
<Directory /home/joe/workspace>
Order allow,deny
Allow from all
</Directory> |
In this particular setup we use very liberal settings, allowing basically everyone with server access to access the directory. Using this approach makes it very easy to use the same test setup but allow testing of different branches/versions of the code.
Depending on the system these configurations can reside in different places.
However, a very common structure is to keep all these small configuration files
under /etc/apache/conf.d/
The main Apache configuration
then reads all the files (regardless of there name) that are stored under this
directory.
As a final example we show a further slightly more complex example (which
actually shows how most of our developers have there systems setup for PHP5
development). This example adds options to do directory listing and allows the
server to follow symbolic links. More information on available argument for the
directive option is available in the official Apache documentation http://httpd.apache.org/docs/2.2/mod/core.html#options
Example 3.5. Alias configuration for a development server running Apache with Eclipse-PDT
1 2 3 4 5 6 7 8 9 10 | # Configuration for Eclipse workspace
#
<IfModule mod_php5.c>
Alias /ws/ /home/joe/workspace/
<Directory /home/joe/workspace/>
Options +Indexes +Multiviews +FollowSymLinks
order allow,deny
allow from all
</Directory>
</IfModule> |