Blog Archives

Howto: change the notification subject and allow KB images in GLPI version 0.90.3

GLPI released their new version 0.90.3.
With new each release two questions seem to be very persistent. These questions are:

  1. How can we change the default notification prefix: [GLPI ] in the email  subject.
  2. How do we enable images in the KB articles.

In this article you will be able to read my personal  opinion on the matter and how to change this GLPI behavior.

Why do you want to change the GLPI  notification prefix.

The most obvious reason is to allow your customer to quickly identify your companies tickets. The rule of thumb in modern system view design is enabling users to quickly: ‘scan, select. act’ Changing the subject to something intuitive enables your customers to do so.

Another point of interest is the possibility to daisy-chain multiple installations of GLPI. By configuring the notification subjects and schemes correctly you can daisy chain multiple installations allowing cross organization enterprise environments to be set up. This is impossible when all installations identify themselfs as ‘GLPI [key].’

How to alter the code to support your custom prefix in GLPI 0.90

In order to alter the subject prefix in GLPI 0.90,  firstly you need to configure your prefix in the Administration>Entities>[your entity]>notifications>Prefix for notifications. Changing this configuration field will correctly alter the prefix to that of your liking. No further code-hacks are required or advised.

Why do you want images in your KB.

Well this is -in my humble opinion- an no brainer. One images shows more detail then i can describe in a thousand words. Images also help speed up the resolution process, especially during nightly hours. It also allows the engineer to intuitively compare the version of the actual situation with the situation documented. Is it all positive then? no, there are some downsides to consider as well.

An image doesn’t replace the engineers know-how and sometimes you want to explicitly trigger this knowledge by not showing any images. Updated applications might look different, actually slowing down the resolution process. Another more technical downside is web server storage. All images need to be stored somewhere and might needlessly clutter the support-system. My point of view is that you need to decide whats best for your situation. Sadly GLPI doesnt allow you to choose yet, it forces images to be removed. If you do need image support, please apply the code-hack below.

Be aware, This wont enable image export to pdf.

How to enable images in the KB

First we need to enable the INSERT function that enables us to add images using the TinyMCE editor. In order to do this two changes need to be made.

In the inc/html.class.php file on line:3837 and line:3871 comment out ( // ) the lines that reads _html = _html.replace .. See screenshots for more details.

Optionally you can enable the ‘image’ button by adding image to the ‘theme_advanced_buttons2 : ‘ line. See images underneath for more details.


The next step is to enable the images to be shown. Without this change the HTMLAWED plugin will add a denied tag to the actual images effectivly telling the browser not to show the image. Additionally the resulting HTML code including the denied: tag will be stored in database also disabling this specific image after the next code modification. Enabling the images afterward requires an search and replace statement in the database. (See comments below).

In the file /lib/htmlawed/htmLawed.php on line 47 add ‘;src: data’ to the end of the line.

Make sure you use an screenshot tool that generates an inline HTML image on the clipboard. Greenshot is an free alternative that does this out of the box.


No tuples available at this result index in […]

Recently I was creating a simple PHP webpage that required an MSSQL connection for a query. I installed the freetds-0.91-15 driver on my Oracle Linux and configured unixODBC-2.2.11-10.el5 appropriately. All went well and I soon had the first results on my page. My next task was to create a simple enough query that would ‘count’ some database rows. Simple enough, right? Well, at least up to the part where I ran into this error:

No tuples available at this result index in […]

All the posts I found referred to multiple result sets in which ‘odbc_next_result($result);’ should be the resolution. The weird part was, pasting of the echoed $sql into the MSSQL query box would give me the desired effect. One result with an count of the rows. The same SQL in the PHP script would give me the ‘no tuples’ error. I nearly fixed it the ugly way (counting the rows in an php while that would work) when I had an insight.

In the mssql output i noticed NULL fields in the table column that I was counting. So i figured, might counting NULL values somehow trigger the ‘No Tuples’ error im getting?

So this is what I ended up testing:

SELECT COUNT([sdk].[Events].[FirstName]) as Counted FROM [sdk].[Events]
WHERE [sdk].[Events].[PeripheralName] like '%Search%'
AND [sdk].[Events].[EventTime] BETWEEN '1' AND '31'

Which resulted in : Warning: odbc_fetch_array(): No tuples available at this result index in /var/www/db.class.php on line 52

SELECT COUNT([sdk].[Events].[FirstName]) as Counted FROM [sdk].[Events]
WHERE [sdk].[Events].[PeripheralName] like '%Search%'
AND [sdk].[Events].[EventTime] BETWEEN '1' AND '31'
AND [sdk].[Events].[FirstName] is not null

Which resulted in an working count query.

Fix the inline images -bug- in glpi knowledgebase (htmLawed.php)

GLPI-0-84-8 FIX

GLPI uses the htmLawed filter to clean inserted HTML code. Documentation on this framework can be found here:

Problem with this framework in GLPI is that it does not match image tags properly when they contain inline base64 information.

Here is a simple fix to overcome this problem. The htmLawed.php file can be located in %glpi_root%/lib/htmlawed/htmLawed.php. Open it with your favorite editor. Next locate line: 47. Somewhere arround that area you should find the following.

Web - sftp___nagios@glpi.amis.nl_var_www_glpi_prod_lib_htmlawed_htmLawed.php - A_2013-10-29_12-34-30

Add ‘data’ at the end of the marked line.

$x = (isset($C['schemes'][2]) && strpos($C['schemes'], ':')) ? strtolower($C['schemes']) : 'href: aim, feed, file, ftp, gopher, http, https, irc, mailto, news, nntp, sftp, ssh, telnet; *:file, http, https, data';

The above will stop htmLawed from adding disabled: to the data: in the src=”” tag.

The next step is a bit trickier.

Now we need to actually change the hl_tag function. In the file locate the hl_tag($t) function somewhere around line:407. In this codeblock we are looking for the regular expression marked in the image below:

Web - sftp___nagios@glpi.amis.nl_var_www_glpi_prod_lib_htmlawed_htmLawed.php - A_2013-10-29_12-38-10

This is the expression that doenst match the valid <img> tags within the htmLawed. We dont want to create leaks here, so all we need to do is introduce an exception for our images. You can do so by replacing the text with the following:

Web - sftp___nagios@glpi.amis.nl_var_www_glpi_test_lib_htmlawed_htmLawed.php - A_2013-10-29_12-49-27

In code:

if(!preg_match('`^&lt;(/?)([a-zA-Z][a-zA-Z1-6]*)([^&gt;]*?)\s?&gt;$`m', $t, $m)){
if(strstr($t, 'data:image')){
return $t;
return str_replace(array('&lt;', '&gt;'), array('&amp;lt;', '&amp;gt;'), $t);
}elseif(!isset($C['elements'][($e = strtolower($m[2]))])){
return (($C['keep_bad']%2) ? str_replace(array('&lt;', '&gt;'), array('&amp;lt;', '&amp;gt;'), $t) : '');

After this, the images should show up just fine

GLPI - Knowledge base_2013-10-29_12-50-51

I hope this was helpfull 🙂

Extract all content to disk from a SPS2007 content DB using PHP

Today I ran into a problem. We needed to migrate a huge amount of data from an old SharePoint 2007 content database without the availability of the MOSS front-end. All i had was the database and a corrupted sharepoint install that wasnt going to help me allot.

To overcome this problem I decided to write a little PHP application that would do this task for me. I allready had WAMP setup on my desktop, so i figured this to be the quickest route. Then i figured, maybe other people face this problem as well. So here it is, the code, and some helpers to get you going.

* @name           : index.php - MSSql Content connector
* @Author        : Chris Gralike
* @version        :
* @copyright     : WETFYWTDWI - what ever ** you want to do with it, no guarantees 🙂
*  This script ONLY READS the database tables, so dont give it more permissions 🙂

// What to search for in the directory structure.
$search = '';
// Where too put the files
$createdir = './Downloaded';
// What server too connect to.
$ServerName = 'amisnt05.amis.local';
// Database connection parameters.
$connectionInfo = array('Database' => 'MOSS_PROD_WSS_Content_WebApp02',
'UID' => 'php_login',
'PWD' => 'welcome12345678');
// This can be a very long task to complete, so disable the timelimit.
// Create a connection
$conn = sqlsrv_connect($ServerName, $connectionInfo)
or die( print_r( sqlsrv_errors(), true));

// The SQL statment to query the AllDocs tables.
$tsql = "SELECT dbo.AllDocs.Id,
dbo.AllDocStreams.Id as StreamId,
FROM dbo.AllDocs
RIGHT OUTER JOIN dbo.AllDocStreams ON dbo.AllDocs.Id = dbo.AllDocStreams.Id
WHERE AllDocs.DirName LIKE '%{$search}%'
AND AllDocs.SetupPath IS NULL
AND AllDocs.Extension != ''
// The result set
$result = sqlsrv_query($conn, $tsql);

// Process the results
while($row = sqlsrv_fetch_array($result,  SQLSRV_FETCH_ASSOC)){
// When create is true, then it will create the folders in
// in the foreach
$create = false;
$dirptr = $createdir;

// Find the folders and recreate them starting from the searchstring.
$folders = explode('/', $row['DirName']);
foreach ($folders as $val){
if($val == $search || $create == true || empty($search)){
$create = true;
$dirptr .= '/'.$val;
echo "INFO: created $dirptr <br/>";
echo "WARN: skipping $dirptr allready exists. <br />";

// Recreate the file
$filepath = $dirptr.'/'.$row['LeafName'];
if($fp = fopen($filepath,'w')){
fwrite($fp, $row['Content']);
echo "INFO: file {$row['LeafName']} written. <br />";
echo "ERROR: file {$row['LeafName']} could not be written in $filepath. <br />";
// Close the database connection.

Simply configure the first vars in the script and run the file. It might take a huge while before you get some output.

TIP: Use the $search to narrow down the query a bit.
It searches the DirName (I.e. Site\DocLib\Folder\SubFolder\)

The output will look like this.

INFO: created ./Downloaded/SearchCenter
INFO: created ./Downloaded/SearchCenter/Pages
INFO: file facetedsearch.aspx written.
WARN: skipping ./Downloaded/SearchCenter allready exists.
WARN: skipping ./Downloaded/SearchCenter/Pages allready exists.
INFO: file resultskeyword.aspx written.

Then please leave a comment 🙂

WARNING!: YOU NEED THE Microsoft MSSQL DRIVER FOR PHP, not the old php equivalent.
here are some tips on where to get it. My version was php 5.3.8

First off, mssql isnt supported out of the box anymore. when using PHP 5.2 and up, you need to get the Microsoft for PHP driver. Check this site for more information :

Its a bit of an hassle ill give you that.
Challenge: I needed 1.5hours to find the correct Lib,Install,Coding info and get it working.

Basically it requires you to download the native client, the drivers and an correct update of the php.ini your wamp instance is using.

Tip: Use <?php phpinfo() ?> to find the right version for your PHP compilation.
Search for : PHP Extension Build : API20090626,TS,VC9


Be sure to verify the SQL query inside the $tsql=” var and alter it accordingly. The other part should be pretty straight forward.

Draw dots in images using PHP, XMLHttp, Mysql.

A family member asked me if it was possible to use html, php, mysql to mark spots in an image of the human skeleton during an medical anamnesis collection. He wanted this to easily mark the complaint spots of his patients. He also needed to be able to remove marks when they where faulty and wanted this all to be stored in a database for easy reference and backup.

Seeing the complexity of it, I accepted the challenge he laid out for me.

The most complex part of this was the ‘how to remove’ spots from an image without deleting the actual fixed image of the skeleton. The solution I came up with was using an Fixed background image in HTML and use a transparent overlay that I will be updating using PHP and XMLHttp request headers.

The result of this approach was the following.

All that needs to be done during reporting is merging both images together, which is fairly easy using php.

But because I though someone else might use this script as well, I thought sharing it here with the world was a nice option. The application is endless, from damage reporting to Location reporting, and in the finished from its fairly easy to understand and adjust to your needs.

I added the sourcecode for this script to this post. You need to have a mysql database, php with GD enabled, browser that supports XHTMLRequest (all modern browsers). Simply dump the files into the a php html enabled location and make sure you create the required SQL table (usign the .sql script inside the archive) and have a go with it (you might need to alter the mysql user/pass inside the PHP script)….


Use the “save as” option to grab the file from this site. Rename the file to, unpack and access the srcfiles inside the rar archive… use winrar to unpack.

Let me know what you think, or if you found it usefull 🙂

p.s. I wasnt able to verify the author of the used skeleton image. If you are/know him, let me know if this application is allowed, and how to publish the credits.

Fixing the monitoring hosts > hosts view in centreon 2.1.4

When opening the Monitoring > Hosts > Hosts view to view all the available and configured hosts in Centreon 2.1.4 you will get a blank result. This happens because there is a coding error in the following file.

/usr/local/centreon/www/include/monitoring/status/Hosts/xml/hostXML.php on line 249

To correct it you need to add a else statement to the if, elseif validation that happens there. So open the file listed above using your fav. editor (vim in my case)

vim /usr/local/centreon/www/include/monitoring/status/Hosts/xml/hostXML.php

Version 2.1.4

Skip to line 249 typing ” :249 ” followed by an enter stroke.
On that line there should be something like;

if (($ndo["last_hard_state_change"] > 0) && ($ndo["last_hard_state_change"] >= $ndo["last_state_change"]))
                        $hard_duration = Duration::toString(time() - $ndo["last_hard_state_change"]);
                else if ($ndo["last_hard_state_change"] > 0)
                        $hard_duration = " N/A ";

Change it to this by adding the part starting from “else”.

if (($ndo["last_hard_state_change"] > 0) && ($ndo["last_hard_state_change"] >= $ndo["last_state_change"]))
                        $hard_duration = Duration::toString(time() - $ndo["last_hard_state_change"]);
                else if ($ndo["last_hard_state_change"] > 0)
                        $hard_duration = " N/A ";
                        $hard_duration = " unknown ";

Version 2.1.8

Goto rule 272 in the same file and locate this piece of code:

if (($ndo["last_hard_state_change"] > 0) && ($ndo["last_hard_state_change"] >= $ndo["last_state_change"]))
                        $hard_duration = Duration::toString(time() - $ndo["last_hard_state_change"]);
                else if ($ndo["last_hard_state_change"] > 0)
                        $hard_duration = " N/A ";

Add the following to make it work.

if (($ndo["last_hard_state_change"] > 0) && ($ndo["last_hard_state_change"] >= $ndo["last_state_change"]))
                        $hard_duration = Duration::toString(time() - $ndo["last_hard_state_change"]);
                else if ($ndo["last_hard_state_change"] > 0)
                        $hard_duration = " N/A ";
                        $hard_duration = "N/A";

This same rule is responsible for the following errors in your apache error_log.

PHP Notice: Undefined variable: hard_duration in /usr/local/centreon/www/include/monitoring/status/Hosts/xml/hostXML.php on line 271, referer:;o=h

This change should fix it for ya.

Grtz, Chris.

Phase one, Check IOStat for Nagios.

Full Working version can be found here



Thanks, Rgrds,

Simple php function to filter out unwanted text char types.

Just wrote a little function that will remove all char types from a string or text (if thats in the string) that are not given in the chars list. In my example I only wanted alpha chars and spaces. It also converts all to lower caps.

It walks through the given string using a substr function to locate the char to be evaluated. If the char is found in the given allowed string using a strstr function it will add it to the return string, else it will simply discard it. Before evaluation it also converts the val to a lowercap.


function cleanstr($s, $c, $l=true){
                $v=substr($s, $i, 1);
                if(strstr($c, $v)){ $r .=$v;}
        return $r;

$string='abcdef $%%# Chris';
$chars=' abcdefhijklmnopqrstuvwxyz';
echo cleanstr($string, $chars);

Prints out…

php ./test.php
abcdef  chris

Resetting the WP-admin account from the commandprompt.

1. Open a bash shell on the linux box. Using SSH is advised.
2. Generate a password MD5 hash using php.

 php -r "print( md5('YourPassWordHere')); print(\"\r\n\");"

3. Copy the 32 bit string that is the result.
4. Connect to mysql


5. Connect to the correct database;

show databases;
use databasename;

6. make a copy/paste backup of the admin user data.

select * from wp_users where user_login = 'admin';

7. Update the table

update wp_users set user_pass='the_md5_hash_generated_in_step_2/3' where user_login = 'admin';

8. Log into wordpress using the username “admin” and the password you have used.

— Suggestion after the comment by kadimi —

9. Reset you password using the “wordpress dashboard > Users > Your profile > Change password” option.

Hide drives in Windows XP.


Drives refference (Binairy), please not that the registry entry (Reg_Dword) is HEX by default.

A: 1, B: 2, C: 4, D: 8, E: 16, F: 32, G: 64, H: 128, I: 256, J: 512, K: 1024, L: 2048, M: 4096, N: 8192, O: 16384, P: 32768, Q: 65536, R: 131072, S: 262144, T: 524288, U: 1048576, V: 2097152, W: 4194304, X: 8388608, Y: 16777216, Z: 33554432, ALL: 67108863

If multiple drives are hidden, then the sum of values apply to the key. I.e.

Hiding “C: & D:”
C: 4 + D: 8 = 12, in which case the regkey should get the value “12” binairy or “12” Hex 😉