Merge pull request #52 from LDAPAccountManager/imageutils

Imageutils
This commit is contained in:
gruberroland 2018-08-25 19:43:50 +02:00 committed by GitHub
commit 5a15f29418
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 601 additions and 372 deletions

View File

@ -8,9 +8,10 @@ Homepage: https://www.ldap-account-manager.org/
Package: ldap-account-manager Package: ldap-account-manager
Architecture: all Architecture: all
Depends: php5 (>= 5.4.26) | php (>= 7), php5-ldap | php-ldap, php5-gd | php-gd, Depends: php5 (>= 5.4.26) | php (>= 7), php5-ldap | php-ldap,
php5-json | php-json, php5-imagick | php-imagick, php5-curl | php-curl, php5-gd | php-gd | php5-imagick | php-imagick,
php5 | php-zip, php5 | php-xml, php5-imagick | php-imagick, php5-json | php-json, php5-curl | php-curl,
php5 | php-zip, php5 | php-xml,
libapache2-mod-php5 | libapache2-mod-php | php5-fpm | php-fpm, libapache2-mod-php5 | libapache2-mod-php | php5-fpm | php-fpm,
php-tcpdf, php-phpseclib (>= 2.0), php-tcpdf, php-phpseclib (>= 2.0),
apache2 (>= 2.4.0) | httpd, fonts-dejavu, debconf (>= 0.2.26) | debconf-2.0, ${misc:Depends} apache2 (>= 2.4.0) | httpd, fonts-dejavu, debconf (>= 0.2.26) | debconf-2.0, ${misc:Depends}

View File

@ -1,7 +1,9 @@
September 2018 6.5 September 2018 6.5
- Password change possible via LDAP EXOP operation (set LDAP_EXOP as password hash) - Password change possible via LDAP EXOP operation (set LDAP_EXOP as password hash, requires PHP 7.2)
- Dropped suppurt for Apache 2.2 - Support Imagick and GD
- Dropped support for Apache 2.2
- Upload: allow to overwrite existing accounts - Upload: allow to overwrite existing accounts
- Personal: photos can be printed in PDF export
- Kolab updates - Kolab updates
- LAM Pro: - LAM Pro:
-> Auto deletion of entries with dynamic directory services support (requires PHP 7.2). -> Auto deletion of entries with dynamic directory services support (requires PHP 7.2).

View File

@ -1,410 +1,407 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" <!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd"> "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
<chapter> <chapter>
<title>Tools</title> <title>Tools</title>
<para></para> <para/>
<section id="a_accountProfile"> <section id="a_accountProfile">
<title>Profile editor</title> <title>Profile editor</title>
<para>The account profiles are templates for your accounts. Here you can <para>The account profiles are templates for your accounts. Here you can
specify default values which can then be loaded when you create specify default values which can then be loaded when you create accounts.
accounts. You may also load a template for an existing account to reset You may also load a template for an existing account to reset it to
it to default values. When you create a new account then LAM will always default values. When you create a new account then LAM will always load
load the profile named <emphasis role="bold">"default"</emphasis>. This the profile named <emphasis role="bold">"default"</emphasis>. This account
account profile can include default values for all your accounts.</para> profile can include default values for all your accounts.</para>
<screenshot> <screenshot>
<mediaobject> <mediaobject>
<imageobject> <imageobject>
<imagedata fileref="images/profileEditor2.png" /> <imagedata fileref="images/profileEditor2.png"/>
</imageobject> </imageobject>
</mediaobject> </mediaobject>
</screenshot> </screenshot>
<para>You can enter the LDAP suffix, RDN identifier and various other <para>You can enter the LDAP suffix, RDN identifier and various other
attributes depending on account type and activated modules.</para> attributes depending on account type and activated modules.</para>
<screenshot> <screenshot>
<mediaobject> <mediaobject>
<imageobject> <imageobject>
<imagedata fileref="images/profileEditor.png" /> <imagedata fileref="images/profileEditor.png"/>
</imageobject> </imageobject>
</mediaobject> </mediaobject>
</screenshot> </screenshot>
<para><emphasis role="bold">Import/export:</emphasis></para> <para><emphasis role="bold">Import/export:</emphasis></para>
<para>Profiles can be exported to and imported from other server <para>Profiles can be exported to and imported from other server
profiles.</para> profiles.</para>
<screenshot> <screenshot>
<mediaobject> <mediaobject>
<imageobject> <imageobject>
<imagedata fileref="images/profileEditor3.png" /> <imagedata fileref="images/profileEditor3.png"/>
</imageobject> </imageobject>
</mediaobject> </mediaobject>
</screenshot> </screenshot>
<screenshot> <screenshot>
<mediaobject> <mediaobject>
<imageobject> <imageobject>
<imagedata fileref="images/profileEditor4.png" /> <imagedata fileref="images/profileEditor4.png"/>
</imageobject> </imageobject>
</mediaobject> </mediaobject>
</screenshot> </screenshot>
<para>There is a special export target called "*Global templates". All <para>There is a special export target called "*Global templates". All
profiles exported here will be copied to all other server profiles profiles exported here will be copied to all other server profiles (incl.
(incl. new ones). But existing profiles with the same name are not new ones). But existing profiles with the same name are not overwritten.
overwritten. So a profile in global templates is treated as default So a profile in global templates is treated as default profile for all
profile for all server profiles.</para> server profiles.</para>
<para>Use this if you would like to setup default profiles that are <para>Use this if you would like to setup default profiles that are valid
valid for all server profiles.</para> for all server profiles.</para>
<screenshot> <screenshot>
<mediaobject> <mediaobject>
<imageobject> <imageobject>
<imagedata fileref="images/profileEditor5.png" /> <imagedata fileref="images/profileEditor5.png"/>
</imageobject> </imageobject>
</mediaobject> </mediaobject>
</screenshot> </screenshot>
</section> </section>
<section> <section>
<title>File upload</title> <title>File upload</title>
<para>When you need to create lots of accounts then you can use LAM's <para>When you need to create lots of accounts then you can use LAM's file
file upload to create them. LAM will read a CSV formatted file and upload to create them. LAM will read a CSV formatted file and create the
create the related LDAP entries. Please check the data in you CSV file related LDAP entries. Please check the data in you CSV file carefully. LAM
carefully. LAM will do less checks for the file upload than for single will do less checks for the file upload than for single account
account creation.</para> creation.</para>
<para>At the first page please select the account type and what <para>At the first page please select the account type and what extensions
extensions should be activated.</para> should be activated.</para>
<screenshot> <screenshot>
<mediaobject> <mediaobject>
<imageobject> <imageobject>
<imagedata fileref="images/fileUpload1.png" /> <imagedata fileref="images/fileUpload1.png"/>
</imageobject> </imageobject>
</mediaobject> </mediaobject>
</screenshot> </screenshot>
<para>The next page shows all available options for the file upload. You <para>The next page shows all available options for the file upload. You
will also find a sample CSV file which can be used as template for your will also find a sample CSV file which can be used as template for your
CSV file. All red options are required columns in the file. You need to CSV file. All red options are required columns in the file. You need to
specify a value for each account.</para> specify a value for each account.</para>
<para>When you upload the CSV file then LAM first does some checks on <para>When you upload the CSV file then LAM first does some checks on this
this file. This includes syntax checks and if all required data was file. This includes syntax checks and if all required data was entered. No
entered. No changes in the LDAP directory are done at this time.</para> changes in the LDAP directory are done at this time.</para>
<para>If the checks were successful then LAM will ask again if you want <para>If the checks were successful then LAM will ask again if you want to
to create the accounts. You will also have the chance to check the create the accounts. You will also have the chance to check the upload by
upload by viewing the changes in LDIF format.</para> viewing the changes in LDIF format.</para>
<screenshot> <screenshot>
<mediaobject> <mediaobject>
<imageobject> <imageobject>
<imagedata fileref="images/fileUpload2.png" /> <imagedata fileref="images/fileUpload2.png"/>
</imageobject> </imageobject>
</mediaobject> </mediaobject>
</screenshot> </screenshot>
</section> </section>
<section> <section>
<title id="toolMultiEdit">Multi edit</title> <title id="toolMultiEdit">Multi edit</title>
<para>This tool allows you to modify a large list of LDAP entries in <para>This tool allows you to modify a large list of LDAP entries in batch
batch mode. You can add new attributes/object classes, remove attributes mode. You can add new attributes/object classes, remove attributes and set
and set attributes to a specific value.</para> attributes to a specific value.</para>
<para>At the beginning, you need to specify where the entries are stored <para>At the beginning, you need to specify where the entries are stored
that should be changed. You can select an account suffix, the tree that should be changed. You can select an account suffix, the tree suffix
suffix or enter your own DN by selecting "Other".</para> or enter your own DN by selecting "Other".</para>
<para>Next, enter an additional LDAP filter to limit the entries that <para>Next, enter an additional LDAP filter to limit the entries that
should be changed. E.g. use "(objectclass=inetOrgPerson)" to filter for should be changed. E.g. use "(objectclass=inetOrgPerson)" to filter for
users. You may also enter e.g. "(!(objectClass=passwordSelfReset))" to users. You may also enter e.g. "(!(objectClass=passwordSelfReset))" to
match all accounts that do not yet have the <link match all accounts that do not yet have the <link
linkend="passwordSelfResetUser">password self reset</link> linkend="passwordSelfResetUser">password self reset</link> feature.</para>
feature.</para>
<literallayout> <literallayout>
</literallayout> </literallayout>
<para>Now, it is time to define the changes that should be done. The <para>Now, it is time to define the changes that should be done. The
following operations are possible:</para> following operations are possible:</para>
<itemizedlist> <itemizedlist>
<listitem> <listitem>
<para>Add: Adds an attribute value if not yet existing. Please do <para>Add: Adds an attribute value if not yet existing. Please do not
not use for single-value attributes that already have a use for single-value attributes that already have a value.</para>
value.</para> </listitem>
</listitem>
<listitem> <listitem>
<para>Modify: Sets an attribute to the given value. If the attribute <para>Modify: Sets an attribute to the given value. If the attribute
does not yet exist then it is added. If the attribute has multiple does not yet exist then it is added. If the attribute has multiple
values then all other values are removed.</para> values then all other values are removed.</para>
</listitem> </listitem>
<listitem> <listitem>
<para>Delete: Deletes the specified value from this attribute. If <para>Delete: Deletes the specified value from this attribute. If you
you leave the value field blank then all attribute values are leave the value field blank then all attribute values are
removed.</para> removed.</para>
</listitem> </listitem>
</itemizedlist> </itemizedlist>
<para>Please note that all actions are run as separate LDAP commands. <para>Please note that all actions are run as separate LDAP commands. You
You cannot add an object class and a required attribute at the same cannot add an object class and a required attribute at the same
time.</para> time.</para>
<screenshot> <screenshot>
<mediaobject> <mediaobject>
<imageobject> <imageobject>
<imagedata fileref="images/multiEdit1.png" /> <imagedata fileref="images/multiEdit1.png"/>
</imageobject> </imageobject>
</mediaobject> </mediaobject>
</screenshot> </screenshot>
<para><emphasis role="bold">Dry run</emphasis></para> <para><emphasis role="bold">Dry run</emphasis></para>
<para>You should always start with a dry run. It will not do any changes <para>You should always start with a dry run. It will not do any changes
to your LDAP directory but print out all modifications that will be to your LDAP directory but print out all modifications that will be done.
done. You will also be able to download the changes in LDIF format to You will also be able to download the changes in LDIF format to use with
use with ldapmodify. This is useful if you want to adjust some actions ldapmodify. This is useful if you want to adjust some actions
manually.</para> manually.</para>
<screenshot> <screenshot>
<mediaobject> <mediaobject>
<imageobject> <imageobject>
<imagedata fileref="images/multiEdit2.png" /> <imagedata fileref="images/multiEdit2.png"/>
</imageobject> </imageobject>
</mediaobject> </mediaobject>
</screenshot> </screenshot>
<para><emphasis role="bold">Apply changes</emphasis></para> <para><emphasis role="bold">Apply changes</emphasis></para>
<para>This will run the actions against your LDAP directory. You will <para>This will run the actions against your LDAP directory. You will see
see which accounts are edited in the progress area and also if any which accounts are edited in the progress area and also if any errors
errors occured.</para> occured.</para>
<screenshot> <screenshot>
<mediaobject> <mediaobject>
<imageobject> <imageobject>
<imagedata fileref="images/multiEdit3.png" /> <imagedata fileref="images/multiEdit3.png"/>
</imageobject> </imageobject>
</mediaobject> </mediaobject>
</screenshot> </screenshot>
</section> </section>
<section> <section>
<title>OU editor</title> <title>OU editor</title>
<para>This is a simple editor to add/delete organisational units in your <para>This is a simple editor to add/delete organisational units in your
LDAP tree. This way you can structure the accounts.</para> LDAP tree. This way you can structure the accounts.</para>
<screenshot> <screenshot>
<mediaobject> <mediaobject>
<imageobject> <imageobject>
<imagedata fileref="images/ouEditor.png" /> <imagedata fileref="images/ouEditor.png"/>
</imageobject> </imageobject>
</mediaobject> </mediaobject>
</screenshot> </screenshot>
</section> </section>
<section id="pdfEditor"> <section id="pdfEditor">
<title>PDF editor</title> <title>PDF editor</title>
<para>All accounts in LAM may be exported as PDF files. You can specify <para>All accounts in LAM may be exported as PDF files. You can specify
the page structure and displayed information by editing the PDF the page structure and displayed information by editing the PDF
profiles.</para> profiles.</para>
<screenshot> <screenshot>
<mediaobject> <mediaobject>
<imageobject> <imageobject>
<imagedata fileref="images/pdfEditor2.png" /> <imagedata fileref="images/pdfEditor2.png"/>
</imageobject> </imageobject>
</mediaobject> </mediaobject>
</screenshot> </screenshot>
<para>When you export accounts to PDF then each account will get its own <para>When you export accounts to PDF then each account will get its own
page inside the PDF. There is a headline on each page where you can show page inside the PDF. There is a headline on each page where you can show a
a page title. You may also add a logo to each page. To add more logos page title. You may also add a logo to each page. To add more logos please
please use the logo management on the PDF editor main page.</para> use the logo management on the PDF editor main page.</para>
<screenshot> <screenshot>
<mediaobject> <mediaobject>
<imageobject> <imageobject>
<imagedata fileref="images/pdfEditor.png" /> <imagedata fileref="images/pdfEditor.png"/>
</imageobject> </imageobject>
</mediaobject> </mediaobject>
</screenshot> </screenshot>
<para>The main part is structured into sections of information. Each <para>The main part is structured into sections of information. Each
section has a title. This can either be static text or the value of an section has a title. This can either be static text or the value of an
attribute. You may also insert a static text block as section. Sections attribute. You may also insert a static text block as section. Sections
can be moved by using the arrows next to the section title.</para> can be moved by using the arrows next to the section title.</para>
<para>Each section can contain multiple fields which usually represent <para>Each section can contain multiple fields which usually represent
LDAP attributes. You can simply add new fields by selecting the field LDAP attributes. You can simply add new fields by selecting the field name
name and its position. Then use the arrows to move the field inside the and its position. Then use the arrows to move the field inside the
section.</para> section.</para>
<literallayout> <literallayout>
</literallayout> </literallayout>
<para><emphasis role="bold">Import/export:</emphasis></para> <para><emphasis role="bold">Import/export:</emphasis></para>
<para>PDF structures can be exported to and imported from other server <para>PDF structures can be exported to and imported from other server
profiles.</para> profiles.</para>
<screenshot>
<mediaobject>
<imageobject>
<imagedata fileref="images/pdfEditor3.png"/>
</imageobject>
</mediaobject>
</screenshot>
<screenshot>
<mediaobject>
<imageobject>
<imagedata fileref="images/pdfEditor4.png"/>
</imageobject>
</mediaobject>
</screenshot>
<para>There is a special export target called "*Global templates". All PDF
structures exported here will be copied to all other server profiles
(incl. new ones). But existing PDF structures with the same name are not
overwritten. So a PDF structure in global templates is treated as default
structure for all server profiles.</para>
<para>Use this if you would like to setup default PDF structures that are
valid for all server profiles.</para>
<screenshot>
<mediaobject>
<imageobject>
<imagedata fileref="images/pdfEditor5.png"/>
</imageobject>
</mediaobject>
</screenshot>
<para><emphasis role="bold">Logo management:</emphasis></para>
<para>You can upload image files to put a custom logo on the PDF files.
The image file name must end with .png or .jpg.</para>
<screenshot>
<mediaobject>
<imageobject>
<imagedata fileref="images/pdfEditor6.png"/>
</imageobject>
</mediaobject>
</screenshot>
</section>
<section>
<title>Schema browser</title>
<para>Here you browse the schema of your LDAP server. You can view what
object classes, attributes, syntaxes and matching rules are available.
This is useful if you need to check if a certain object class is
available.</para>
<screenshot>
<mediaobject>
<imageobject>
<imagedata fileref="images/schemaBrowser.png"/>
</imageobject>
</mediaobject>
</screenshot>
</section>
<section>
<title>Server information</title>
<para>This shows information and statistics about your LDAP server. This
includes the suffixes, used overlays, connection data and operation
statistics. You will need "cn=monitor" setup to see all details. Some data
may not be available depending on your LDAP server software.</para>
<para>Please see the following links how to setup "cn=monitor":</para>
<itemizedlist>
<listitem>
<para><ulink
url="http://www.openldap.org/doc/admin24/monitoringslapd.html">OpenLDAP</ulink></para>
</listitem>
<listitem>
<para><ulink type=""
url="http://directory.fedoraproject.org/wiki/Howto:CN%3DMonitor_LDAP_Monitoring">389
server</ulink></para>
</listitem>
</itemizedlist>
<screenshot>
<mediaobject>
<imageobject>
<imagedata fileref="images/serverInfo.png"/>
</imageobject>
</mediaobject>
</screenshot>
</section>
<section>
<title>Tests</title>
<para>This allows you to check if your LDAP schema is compatible with LAM
and to find possible problems.</para>
<section>
<title>Lamdaemon test</title>
<para>LAM provides an external script to manage home directories and
quotas. You can test here if everything is setup correctly.</para>
<para>If you get an error like "no tty present and no askpass program
specified" then the path to the lamdaemon.pl may be wrong. Please see
the <link linkend="a_lamdaemon">lamdaemon installation
instructions</link> for setup details.</para>
<screenshot> <screenshot>
<mediaobject> <mediaobject>
<imageobject> <imageobject>
<imagedata fileref="images/pdfEditor3.png" /> <imagedata fileref="images/lamdaemonTest.png"/>
</imageobject>
</mediaobject>
</screenshot>
<screenshot>
<mediaobject>
<imageobject>
<imagedata fileref="images/pdfEditor4.png" />
</imageobject>
</mediaobject>
</screenshot>
<para>There is a special export target called "*Global templates". All
PDF structures exported here will be copied to all other server profiles
(incl. new ones). But existing PDF structures with the same name are not
overwritten. So a PDF structure in global templates is treated as
default structure for all server profiles.</para>
<para>Use this if you would like to setup default PDF structures that
are valid for all server profiles.</para>
<screenshot>
<mediaobject>
<imageobject>
<imagedata fileref="images/pdfEditor5.png" />
</imageobject>
</mediaobject>
</screenshot>
<para><emphasis role="bold">Logo management:</emphasis></para>
<para>You can upload image files to put a custom logo on the PDF files.
The image file name must end with .png or .jpg and the size must not
exceed 2000x300px.</para>
<screenshot>
<mediaobject>
<imageobject>
<imagedata fileref="images/pdfEditor6.png" />
</imageobject> </imageobject>
</mediaobject> </mediaobject>
</screenshot> </screenshot>
</section> </section>
<section> <section>
<title>Schema browser</title> <title>Schema test</title>
<para>Here you browse the schema of your LDAP server. You can view what <para>This will test if your LDAP schema supports all object classes and
object classes, attributes, syntaxes and matching rules are available. attributes of the active LAM modules. If you get a message that
This is useful if you need to check if a certain object class is something is missing please check that you installed all <link
available.</para> linkend="a_schema">required schemas</link>.</para>
<para>If you get error messages about object class violations then this
test can tell you what is missing.</para>
<screenshot> <screenshot>
<mediaobject> <mediaobject>
<imageobject> <imageobject>
<imagedata fileref="images/schemaBrowser.png" /> <imagedata fileref="images/schemaTest.png"/>
</imageobject> </imageobject>
</mediaobject> </mediaobject>
</screenshot> </screenshot>
</section> </section>
</section>
<section> </chapter>
<title>Server information</title>
<para>This shows information and statistics about your LDAP server. This
includes the suffixes, used overlays, connection data and operation
statistics. You will need "cn=monitor" setup to see all details. Some
data may not be available depending on your LDAP server software.</para>
<para>Please see the following links how to setup "cn=monitor":</para>
<itemizedlist>
<listitem>
<para><ulink
url="http://www.openldap.org/doc/admin24/monitoringslapd.html">OpenLDAP</ulink></para>
</listitem>
<listitem>
<para><ulink type=""
url="http://directory.fedoraproject.org/wiki/Howto:CN%3DMonitor_LDAP_Monitoring">389
server</ulink></para>
</listitem>
</itemizedlist>
<screenshot>
<mediaobject>
<imageobject>
<imagedata fileref="images/serverInfo.png" />
</imageobject>
</mediaobject>
</screenshot>
</section>
<section>
<title>Tests</title>
<para>This allows you to check if your LDAP schema is compatible with
LAM and to find possible problems.</para>
<section>
<title>Lamdaemon test</title>
<para>LAM provides an external script to manage home directories and
quotas. You can test here if everything is setup correctly.</para>
<para>If you get an error like "no tty present and no askpass program
specified" then the path to the lamdaemon.pl may be wrong. Please see
the <link linkend="a_lamdaemon">lamdaemon installation
instructions</link> for setup details.</para>
<screenshot>
<mediaobject>
<imageobject>
<imagedata fileref="images/lamdaemonTest.png" />
</imageobject>
</mediaobject>
</screenshot>
</section>
<section>
<title>Schema test</title>
<para>This will test if your LDAP schema supports all object classes
and attributes of the active LAM modules. If you get a message that
something is missing please check that you installed all <link
linkend="a_schema">required schemas</link>.</para>
<para>If you get error messages about object class violations then
this test can tell you what is missing.</para>
<screenshot>
<mediaobject>
<imageobject>
<imagedata fileref="images/schemaTest.png" />
</imageobject>
</mediaobject>
</screenshot>
</section>
</section>
</chapter>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 59 KiB

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.6 KiB

After

Width:  |  Height:  |  Size: 9.0 KiB

View File

@ -3,6 +3,7 @@ use \LAM\PDF\PDFLabelValue;
use \LAM\PDF\PDFTable; use \LAM\PDF\PDFTable;
use LAM\TYPES\ConfiguredType; use LAM\TYPES\ConfiguredType;
use function LAM\TYPES\getScopeFromTypeId; use function LAM\TYPES\getScopeFromTypeId;
use LAM\PDF\PDFImage;
/* /*
This code is part of LDAP Account Manager (http://www.ldap-account-manager.org/) This code is part of LDAP Account Manager (http://www.ldap-account-manager.org/)
@ -846,6 +847,19 @@ abstract class baseModule {
$result[get_class($this) . '_' . $name][] = $table; $result[get_class($this) . '_' . $name][] = $table;
} }
/**
* Adds an image to the PDF.
*
* @param array $result result array (entry will be added here)
* @param String $attrName attribute name
* @param PDFTable $table table
*/
public function addPDFImage(&$result, $attrName) {
if (isset($this->attributes[$attrName]) && (sizeof($this->attributes[$attrName]) > 0)) {
$result[get_class($this) . '_' . $attrName][] = new PDFImage($this->attributes[$attrName][0]);
}
}
/** /**
* Returns an array containing all input columns for the file upload. * Returns an array containing all input columns for the file upload.
* *

View File

@ -81,13 +81,9 @@ if (! function_exists('utf8_decode') || !extension_loaded('xml')) {
if (!extension_loaded('libxml')) { if (!extension_loaded('libxml')) {
$criticalErrors[] = array("ERROR", "Your PHP has no Lib XML support!", "Please install the Lib XML extension for PHP."); $criticalErrors[] = array("ERROR", "Your PHP has no Lib XML support!", "Please install the Lib XML extension for PHP.");
} }
// imagick // imagick/GD
if (!extension_loaded('imagick')) { if (!extension_loaded('imagick') && !function_exists('getimagesize')) {
$criticalErrors[] = array("ERROR", "Your PHP has no imagick support.", "Please install the imagick extension for PHP."); $criticalErrors[] = array("ERROR", "Your PHP has no imagick or GD support.", "Please install the imagick or GD extension for PHP.");
}
// check if PHP has GD support
if (! function_exists('getimagesize')) {
$criticalErrors[] = array("ERROR", "Your PHP has no GD support!", "Please install the GD extension for PHP.");
} }
// check if PHP has JSON support // check if PHP has JSON support
if (! function_exists('json_encode')) { if (! function_exists('json_encode')) {

View File

@ -44,6 +44,20 @@ class ImageManipulationFactory {
if (extension_loaded('imagick')) { if (extension_loaded('imagick')) {
return new ImageManipulatorImagick($imageData); return new ImageManipulatorImagick($imageData);
} }
return new ImageManipulatorGd($imageData);
}
/**
* Returns an image manipulator based on installed PHP modules.
*
* @param string $path path to image file
* @return ImageManipulator manipulator
*/
public static function getImageManipulatorFromFile($path) {
$handle = fopen($path, "r");
$data = fread($handle, 100000000);
fclose($handle);
return ImageManipulationFactory::getImageManipulator($data);
} }
} }
@ -130,7 +144,7 @@ class ImageManipulatorImagick implements ImageManipulator {
* @see \LAM\ImageUtils\ImageManipulator::getHeight() * @see \LAM\ImageUtils\ImageManipulator::getHeight()
*/ */
public function getHeight() { public function getHeight() {
$this->image->getimageheight(); return $this->image->getimageheight();
} }
/** /**
@ -138,7 +152,7 @@ class ImageManipulatorImagick implements ImageManipulator {
* @see \LAM\ImageUtils\ImageManipulator::getWidth() * @see \LAM\ImageUtils\ImageManipulator::getWidth()
*/ */
public function getWidth() { public function getWidth() {
$this->image->getimagewidth(); return $this->image->getimagewidth();
} }
/** /**
@ -157,15 +171,19 @@ class ImageManipulatorImagick implements ImageManipulator {
public function crop($x, $y, $width, $height) { public function crop($x, $y, $width, $height) {
$this->image->cropimage($width, $height, $x, $y); $this->image->cropimage($width, $height, $x, $y);
} }
/** /**
* {@inheritDoc} * {@inheritDoc}
* @see \LAM\ImageUtils\ImageManipulator::resize() * @see \LAM\ImageUtils\ImageManipulator::resize()
*/ */
public function thumbnail($width, $height) { public function thumbnail($width, $height) {
if (($this->getWidth() <= $width) && ($this->getHeight() <= $height)) {
// skip if smaller than target size
return;
}
$this->image->thumbnailimage($width, $height, true); $this->image->thumbnailimage($width, $height, true);
} }
/** /**
* {@inheritDoc} * {@inheritDoc}
* @see \LAM\ImageUtils\ImageManipulator::getImageData() * @see \LAM\ImageUtils\ImageManipulator::getImageData()
@ -176,5 +194,134 @@ class ImageManipulatorImagick implements ImageManipulator {
} }
/**
* Manipulates images using gd library.
*
* @author Roland Gruber
*/
class ImageManipulatorGd implements ImageManipulator {
/**
* Image
*
* @var resource image
*/
private $image;
/**
* GD image type
*
* @var int image type
*/
private $type;
/**
* Constructor.
*
* @param string $imageData original image as binary string
*/
public function __construct($imageData) {
$this->image = imagecreatefromstring($imageData);
$info = getimagesizefromstring($imageData);
$this->type = $info[2];
}
/**
* Destructor
*/
public function __destruct() {
if ($this->image != null) {
imagedestroy($this->image);
}
}
/**
* {@inheritDoc}
* @see \LAM\ImageUtils\ImageManipulator::getHeight()
*/
public function getHeight() {
return imagesy($this->image);
}
/**
* {@inheritDoc}
* @see \LAM\ImageUtils\ImageManipulator::getWidth()
*/
public function getWidth() {
return imagesx($this->image);
}
/**
* {@inheritDoc}
* @see \LAM\ImageUtils\ImageManipulator::getAsJpeg()
*/
public function convertToJpeg() {
$this->type = IMAGETYPE_JPEG;
}
/**
* {@inheritDoc}
* @see \LAM\ImageUtils\ImageManipulator::crop()
*/
public function crop($x, $y, $width, $height) {
$this->image = imagecrop($this->image, array(
'x' => $x,
'y' => $y,
'width' => $width,
'height' => $height
));
}
/**
* {@inheritDoc}
* @see \LAM\ImageUtils\ImageManipulator::resize()
*/
public function thumbnail($width, $height) {
if (($this->getWidth() <= $width) && ($this->getHeight() <= $height)) {
// skip if smaller than target size
return;
}
$thumbWidth = $this->getWidth();
$thumbHeight = $this->getHeight();
if ($thumbWidth > $width) {
$factor = $width / $thumbWidth;
$thumbWidth = $thumbWidth * $factor;
$thumbHeight = $thumbHeight * $factor;
}
if ($thumbHeight > $height) {
$factor = $height / $thumbHeight;
$thumbWidth = $thumbWidth * $factor;
$thumbHeight = $thumbHeight * $factor;
}
$thumbnail = imagecreatetruecolor($thumbWidth, $thumbHeight);
imagecopyresampled(
$thumbnail,
$this->image,
0, 0, 0, 0,
$thumbWidth,
$thumbHeight,
$this->getWidth(),
$this->getHeight());
$this->image = $thumbnail;
}
/**
* {@inheritDoc}
* @see \LAM\ImageUtils\ImageManipulator::getImageData()
*/
public function getImageData() {
ob_start();
if ($this->type == IMAGETYPE_JPEG) {
imagejpeg($this->image);
}
else if ($this->type == IMAGETYPE_PNG) {
imagepng($this->image);
}
$output = ob_get_contents();
ob_clean();
return $output;
}
}
?> ?>

View File

@ -2,7 +2,7 @@
namespace LAM\PDF; namespace LAM\PDF;
/* /*
This code is part of LDAP Account Manager (http://www.ldap-account-manager.org/) This code is part of LDAP Account Manager (http://www.ldap-account-manager.org/)
Copyright (C) 2017 Roland Gruber Copyright (C) 2017 - 2018 Roland Gruber
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -69,7 +69,6 @@ class LAMTCPDF extends \TCPDF {
$logoFile = $this->structure->getLogo(); $logoFile = $this->structure->getLogo();
if (!empty($logoFile) && ($logoFile !== 'none')) { if (!empty($logoFile) && ($logoFile !== 'none')) {
$logo = dirname(__FILE__) . "/../config/pdf/" . $_SESSION['config']->getName() . "/logos/" . $logoFile; $logo = dirname(__FILE__) . "/../config/pdf/" . $_SESSION['config']->getName() . "/logos/" . $logoFile;
$imgProperties = getimagesize($logo);
$this->Image($logo, 10, 10, '', 15, 'JPG', '', 'T', false, 300, '', false, false, 0, false, false, false); $this->Image($logo, 10, 10, '', 15, 'JPG', '', 'T', false, 300, '', false, false, 0, false, false, false);
} }
else { else {

View File

@ -1,6 +1,7 @@
<?php <?php
use \LAM\TYPES\TypeManager; use \LAM\TYPES\TypeManager;
use LAM\ImageUtils\ImageManipulationFactory; use LAM\ImageUtils\ImageManipulationFactory;
use LAM\PDF\PDFImage;
/* /*
This code is part of LDAP Account Manager (http://www.ldap-account-manager.org/) This code is part of LDAP Account Manager (http://www.ldap-account-manager.org/)
@ -556,6 +557,9 @@ class inetOrgPerson extends baseModule implements passwordService {
if (!$this->isBooleanConfigOptionSet('inetOrgPerson_hideInitials')) { if (!$this->isBooleanConfigOptionSet('inetOrgPerson_hideInitials')) {
$return['PDF_fields']['initials'] = _('Initials'); $return['PDF_fields']['initials'] = _('Initials');
} }
if (!$this->isBooleanConfigOptionSet('inetOrgPerson_hidejpegPhoto')) {
$return['PDF_fields']['jpegPhoto'] = _('Photo');
}
// help Entries // help Entries
$return['help'] = array ( $return['help'] = array (
'description' => array ( 'description' => array (
@ -2014,6 +2018,7 @@ class inetOrgPerson extends baseModule implements passwordService {
else if (isset($this->attributes['INFO.userPasswordClearText'])) { else if (isset($this->attributes['INFO.userPasswordClearText'])) {
$this->addPDFKeyValue($return, 'userPassword', _('Password'), $this->attributes['INFO.userPasswordClearText']); $this->addPDFKeyValue($return, 'userPassword', _('Password'), $this->attributes['INFO.userPasswordClearText']);
} }
$this->addPDFImage($return, 'jpegPhoto');
return $return; return $return;
} }

View File

@ -1,5 +1,7 @@
<?php <?php
namespace LAM\PDF; namespace LAM\PDF;
use LAM\ImageUtils\ImageManipulationFactory;
/* /*
This code is part of LDAP Account Manager (http://www.ldap-account-manager.org/) This code is part of LDAP Account Manager (http://www.ldap-account-manager.org/)
Copyright (C) 2003 - 2004 Michael Duergner Copyright (C) 2003 - 2004 Michael Duergner
@ -144,6 +146,9 @@ function createPdf($structure, $accounts, $pdfKeys, $account_type, $font, $retur
else if ($valueEntry instanceof PDFTable) { else if ($valueEntry instanceof PDFTable) {
printTable($pdf, $valueEntry, $font); printTable($pdf, $valueEntry, $font);
} }
else if ($valueEntry instanceof PDFImage) {
printImage($pdf, $valueEntry, $font);
}
} }
} }
} }
@ -231,6 +236,28 @@ function printTable(&$pdf, $table, $fontName) {
$pdf->Ln(LAMPDF_LINEHEIGHT); $pdf->Ln(LAMPDF_LINEHEIGHT);
} }
/**
* Prints a PDFLabelValue entry.
*
* @param LAMTCPDF $pdf PDF
* @param PDFImage $imageEntry entry
* @param string $fontName font name
*/
function printImage(&$pdf, $imageEntry, $fontName) {
include_once dirname(__FILE__) . '/imageutils.inc';
$imageManipulator = ImageManipulationFactory::getImageManipulator($imageEntry->getImageData());
$height = $imageManipulator->getHeight() / 2.9;
if ($height > 40) {
$height = 40;
}
$pdf->Image('@' . $imageManipulator->getImageData(), null, null, null, $height,
'JPG', null, 'T', true, 300, 'R',
false, false, 0, false, false, false);
$pdf->Ln($height);
$pdf->Ln(LAMPDF_LINEHEIGHT);
$imageManipulator = null;
}
/** /**
* Common interface for all PDF entries. * Common interface for all PDF entries.
* *
@ -381,3 +408,41 @@ class PDFLabelValue implements PDFEntry {
} }
} }
/**
* Adds an image to the PDF file.
*
* @package PDF
* @author Roland Gruber
*/
class PDFImage implements PDFEntry {
private $binaryData;
/**
* Constructor
*
* @param string $binaryData image data
*/
public function __construct($binaryData) {
$this->binaryData = $binaryData;
}
/**
* {@inheritDoc}
* @see \LAM\PDF\PDFEntry::getHeadline()
*/
public function getHeadline() {
return '';
}
/**
* Returns the image data.
*
* @return string image data
*/
public function getImageData() {
return $this->binaryData;
}
}

View File

@ -3,6 +3,7 @@ namespace LAM\PDF;
use \htmlStatusMessage; use \htmlStatusMessage;
use \LAMException; use \LAMException;
use \LAM\ImageUtils\ImageManipulationFactory;
/* /*
This code is part of LDAP Account Manager (http://www.ldap-account-manager.org/) This code is part of LDAP Account Manager (http://www.ldap-account-manager.org/)
Copyright (C) 2003 - 2006 Michael Duergner Copyright (C) 2003 - 2006 Michael Duergner
@ -102,10 +103,11 @@ function getAvailableLogos() {
$dirHandle = opendir($dirPath); $dirHandle = opendir($dirPath);
while($file = readdir($dirHandle)) { while($file = readdir($dirHandle)) {
if(!is_dir($file) && $file != '.' && $file != '..' && preg_match('/\\.(jpg|png)$/i',$file)) { if(!is_dir($file) && $file != '.' && $file != '..' && preg_match('/\\.(jpg|png)$/i',$file)) {
$infos = getimagesize($dirPath . $file); include_once dirname(__FILE__) . '/imageutils.inc';
if($infos[0] <= 2000 && $infos[1] <= 300) { $imageManipulator = ImageManipulationFactory::getImageManipulatorFromFile($dirPath . $file);
array_push($return, array('filename' => $file, 'infos' => $infos)); $infos = array($imageManipulator->getWidth(), $imageManipulator->getHeight());
} $imageManipulator = null;
array_push($return, array('filename' => $file, 'infos' => $infos));
} }
} }
sort($return); sort($return);
@ -169,18 +171,14 @@ function uploadPDFLogo($file, $name) {
if (!preg_match('/[a-zA-Z0-9_-]+\\.(png)|(jpg)/i', $name)) { if (!preg_match('/[a-zA-Z0-9_-]+\\.(png)|(jpg)/i', $name)) {
return new htmlStatusMessage('ERROR', _('Unable to upload logo file.'), _('The file name must end with ".png" or ".jpg".')); return new htmlStatusMessage('ERROR', _('Unable to upload logo file.'), _('The file name must end with ".png" or ".jpg".'));
} }
$infos = getimagesize($file); $dirPath = dirname(__FILE__) . '/../config/pdf/' . $_SESSION['config']->getName() . '/logos/';
if ($infos[0] <= 2000 && $infos[1] <= 300) { $success = copy($file, $dirPath . '/' . $name);
$dirPath = dirname(__FILE__) . '/../config/pdf/' . $_SESSION['config']->getName() . '/logos/'; if ($success) {
$success = copy($file, $dirPath . '/' . $name); return new htmlStatusMessage('INFO', _('Uploaded logo file.'), $name);
if ($success) { }
return new htmlStatusMessage('INFO', _('Uploaded logo file.'), $name); else {
} return new htmlStatusMessage('ERROR', _('Unable to upload logo file.'), $name);
else {
return new htmlStatusMessage('ERROR', _('Unable to upload logo file.'), $name);
}
} }
return new htmlStatusMessage('ERROR', _('Unable to upload logo file.'), _('The file must not exeed 2000x300px.'));
} }
/** /**

View File

@ -1,4 +1,6 @@
<?php <?php
use LAM\ImageUtils\ImageManipulationFactory;
/* /*
This code is part of LDAP Account Manager (http://www.ldap-account-manager.org/) This code is part of LDAP Account Manager (http://www.ldap-account-manager.org/)
@ -754,15 +756,18 @@ class lamUserList extends lamList {
fwrite($outjpeg, $entry[$attribute][0]); fwrite($outjpeg, $entry[$attribute][0]);
fclose ($outjpeg); fclose ($outjpeg);
$photoFile = '../../tmp/' . $jpeg_filename; $photoFile = '../../tmp/' . $jpeg_filename;
$imgSize = getimagesize($photoFile); include_once dirname(__FILE__) . '/../imageutils.inc';
$imageManipulator = ImageManipulationFactory::getImageManipulator($entry[$attribute][0]);
$imgHeight = $imageManipulator->getHeight();
$imageManipulator = null;
$minSize = 64; $minSize = 64;
if ($imgSize[0] < 64) { if ($imgHeight < 64) {
$minSize = $imgSize[0]; $minSize = $imgHeight;
} }
$imgTitle = _('Click to switch between thumbnail and original size.'); $imgTitle = _('Click to switch between thumbnail and original size.');
echo "<img id=\"img$imgNumber\" title=\"$imgTitle\" height=$minSize src=\"" . $photoFile . "\" alt=\"" . _('Photo') . "\">"; echo "<img id=\"img$imgNumber\" title=\"$imgTitle\" height=$minSize src=\"" . $photoFile . "\" alt=\"" . _('Photo') . "\">";
echo '<script type="text/javascript">'; echo '<script type="text/javascript">';
echo "addResizeHandler(document.getElementById(\"img$imgNumber\"), $minSize, " . $imgSize[1] . ")"; echo "addResizeHandler(document.getElementById(\"img$imgNumber\"), $minSize, " . $imgHeight . ")";
echo '</script>'; echo '</script>';
} }
elseif (($attribute == 'mail') || ($attribute == 'rfc822Mailbox')) { elseif (($attribute == 'mail') || ($attribute == 'rfc822Mailbox')) {