Generating Invoice PDFs

I need to generate PDF files for invoices. How hard can it be? My project is developed using PHP, so I first had a look at the available PDF libraries for PHP.


TCPDF is a project to generate PDF files from PHP. It is available since 2002 and is used in many projects. However, there are a few concerns:

  • The API is not object oriented, but uses one huge TCPDF class. It uses PHP constants for several configuration options and the API does not use constants, but strings.
  • Example: To create a new TCPDF object with the page format A4 and mm as units, you would use: new TCPDF(‘P’, ‘mm’, ‘A4’);
  • The biggest showstopper is that configuration for fonts takes place using PHP constants, which, once defined, cannot be changed. That means that it is very hard to integrate TCPDF into Symfony2.


ZendPDF is the PDF class from the Zend Framework. I have looked at ZendPDF Version 2. Given the repository activity on GitHub, it seems that ZendPDF is not really maintained and documentation is completely missing.


PhantomJS is a headless web browser based on WebKit, which can also be used to render the output of a HTML page to a file. Unfortunately, phantomjs has a serious kerning problem as seen here: Example PDF. The exact same issue occurs using wkhtmltopdf.


LaTeX is…well…LaTeX. Either you have it or you love it. In my case, the lack of experience with LaTeX and struggling for 2 hours implementing a proper footer placed LaTeX on the bottom of the priority list.

Web-based services

I had a look at several web-based invoicing solutions, including Sage One and Freshbooks. Sage One didn’t support downloading of invoice PDFs via the API, and Freshbooks wasn’t able to produce invoices switchable date formats per invoice.


Right now, my best bet is probably using LaTeX. I might update this post at a later point


OneTimeMail: Reducing mail for evaluating web services

When you sign up to a web service these days, you often only want to try things out. Vendors will usually send you emails, followed by special offers, how to use their products and so on.

I often tend to forget to cancel accounts, so my Inbox gets filled with many mails I have to manually sort and delete. In order to reduce the amounts of mail, I implemented a little filter rule to automatically filter mails for web services which I evaluate.

In order to do that, I follow the convention of adding -otm-<vendor> to the mail I’m registering at those web services. For example, if my email was, and I would want to sign up with Google, I would sign up with

As my mails are hosted at uberspace, I created a simply mailfilter rule:

Now all OneTimeMails are moved to a subdirectory of my inbox. I still can retrieve the mails if required (to click activation links for example), but my main Inbox is now cleaner.

DHL Shipping Labels, Adobe Reader and HP Printers

Printers. They suck since I started using them. But often, drivers are the real culprit. The task was simple: Print DHL shipping labels on one paper tray, and A4 stuff on the other tray. The printer in question is a HP P3015 with one additional tray. A4 sits in tray 3, the A5 shipping labels in tray 2. However, this isn’t as simple as it may sound.

Adobe Reader has an option to automatically select the paper tray based on paper size. Initially I thought: “Well, that’s pretty much what I want”. But after some testing, I encountered those symptoms:

  • When printing A4 paper, often the printer would decide that I have to feed him from Tray 1 (manual feed) instead of the A4 paper sitting in tray 3.
  • When printing A5 shipping labels, the printer requires the user to confirm each page on the menu for Tray 2.
  • The printer driver often ignores the tray setting and tries to print from tray 1, regardless of the selected paper format or available paper

One major issue with that setup is that DHL supplies DIN A5 labels, but their PDF is in some envelope format – that’s why Adobe Reader most likely can’t choose the correct paper tray. And even if it did, the HP driver seems to have some major bugs regarding paper tray selection.

After fiddling around with the drivers for 2 hours, I decided to do the following setup:

  • 2 Printer Drivers for the same printer (in my case, HP P3015 DIN A4 and HP P3015 DIN A5)
  • Each printer has set the other paper trays to be not available
  • Removal of “Automatically select paper size” in Adobe Reader

This setup works now, but it isn’t optimal, as the user needs to switch between the two printer drivers – but at least this works now.

cryptsetup-1.6.6 breaks my crypto! BLARGH!

I updated my NAS server today, which runs on Debian Jessie (testing). After upgrading to cryptsetup-1.6.6, I noticed that my main share didn’t mount anymore. I investigated, and a very odd thing happened while entering the passphrase: cryptsetup took *any* key I entered!

Well, that’s not entirely true. Usually, cryptsetup asks multiple times if the key is wrong, but in my case, it silently dropped me back to my shell without any information.  Running cryptsetup with –verbose revealed that there was:

My heart stopped for a second, because I thought: SHIT, there’s something wrong with the physical disk! Of course, everything was okay – cryptsetup-1.6.6 has a bug which obviously has problems decrypting at least one cipher I use. That particular version of cryptsetup actually did decrypt my other crypto.

Here’s the luksDump info of the drive cryptsetup-1.6.6 couldn’t open:

To downgrade to a more stable version of cryptsetup, I added the stable repo:

Then I pinned the versions of cryptsetup, cryptsetup-bin and libcryptsetup4 to their stable versions:

After running apt-get update, the system should downgrade to cryptsetup-1.4.4. In my case, luksOpen did work again. WHEW!

Hacking and Living on Lanzarote: Day 0 and 1

Day 0

After a flight of only 4 hours I arrived at 8:30AM at Lanzarote Airport. I only got maybe two hours of sleep, but at least everything with my luggage was okay. We went shopping for food and checked out an abandoned building site which was supposed to become a tourist centre. In the evening, David cooked a nice meal and we were discussing plans on how to proceed.

Day 1

We started to dig a hole for a toilet at the place where we are currently staying to do a favor to the owner. The hole needs to be 2m deep, and we made like half a meter of progress. We made a nice time lapse video of it:

We then headed for an abandoned dam to see if it would be suitable to live in. We were hiking for an hour to reach the top of the mountain, and eventually got down to the dam. It was in pretty good shape, however, there isn’t much space inside the dam to use. We talked to a local who told us that there were actually people living inside the dam, and the police eventually came and threw them out.

We discussed a few ideas about how to get sponsorship and talked to a few other locals about opportunities to buy land.

In the evening, David cooked a nice meal and we set up syncthing in order to be able to share files without the need for an online connection.

Hacking and Living on Lanzarote: Day -2 and -1

B3pnrhaIMAEsitLThe last two days were pretty “straightforward”, so this is just a mini update. Packed my bags and I’m pretty sure I missed several important things. I’m sitting in the train heading for Frankfurt, where I have to switch trains to Frankfurt Airport. I’ll arive there approx 1:30 AM so I should have plenty of time for baggage check in – flight departures at 4:45 AM. Unfortunately my estimate for the baggage weight was too optimistic, so I had to leave a few things at home, including the solar battery, the panel, my multimeter and several minor stuff. As I’m heading for the congress on Dec 23rd, I should be able to bring the other stuff as well if I decide to continue with the Lanzarote adventure.

I expect that there will be some minor trouble at the airport regarding the electronics stuff and the Li-Ion batteries for my E-Cigarette as well as weight issues as my body scale isn’t that accurate. I pretty much maxed out the weight restrictions (20kg for the main bag and 6kg for the carry-on baggage. I also noticed that it’s pretty hard to follow all guidelines to put what item in which bag and I’m seriously thinking about creating a web app where you choose your bag contents and the app guides you what to put where, especially for potentially dangerous goods like Lead-Gel batteries as well as medicine. They are allowed on most airlines, but you might need to contact your airline before your flight and supply material safety datasheets. I know that there are websites where you can look stuff up, but it’s much easier to simply specify an item and get recommendations on what to do. For Lead-Gel batteries it’s important to protect the contacts against accidential shorts. Also I noticed that there’s no “how to ship stuff cheap from A to B” web app which guides you through the cheapest logistics company, otherwise I would have simply shipped the panel and batteries via a logistics carrier. Did you know that you can ship “letters” in a box format up to 500 grams pretty cheaply from Germany to almost anywhere in the world for about 3,45 Euro and up to 1 kg for 7 Euro? Maybe two interesting projects to realize.

Hacking and Living on Lanzarote: Day -3

I travelled from Berlin to my home town in order to pick up stuff for the Lanzarote trip. When I stepped out of the bus in Mannheim, my depression almost immediately kicked in. For me, this is a definite sign that the environment is not suitable for my further progress.

I was not sure if it would be a good idea to tell my mother that I’ll be on Lanzarote, but I eventually called her up. She’s for holiday on Fuerteventura, and was understandably confused about my plans. What’s not understandable is the immediate negative vibe she communicated to me. Instead of: “Sounds interesting, what are you doing there?” and wishing me good luck, she covered me with negative aspects of the idea, including missing medical treatment on Lanzarote (which is not true), that I should see my therapist before leaving and so on. I am pretty much sure that she will read this blog post sometime near in the future, but I’m not scared anymore. From every person I’ve told about the Lanzarote plans, I only got positive feedback so far, which confirms that I am on the right track.

What I failed to communicate to my mother is that hackers and nerds are different. We care for each other, and even due to the fact that I had to leave the hacker-hippie-flat in Berlin doesn’t mean that I’m mad with my former flatmates. The essence of us hackers is that we try new things, we explore and make the impossible possible. We communicate mostly open-minded and find new approaches and solutions. We build up huge camps with fast internet and 3000+ people camp every 2 years in the middle of nowhere. We organize the yearly Chaos Communication Congress for 4000+ people. We enable people to get internet access for free using the Freifunk project. We share our inventions, our procedures, our projects and our knowledge.

We are crossing the boundaries for the greater good. We are changing the world. Together. One small step at a time.

If you like to call that crazy, then I guess we are crazy. But it’s more likely that we have a different mind set.

Hacking and Living on Lanzarote – Day -4

My stomach wasn’t that well today, and my mood wasn’t either. I had some doubts if Lanzarote is really the right choice in case something happens to my health. On the other side, I’ve been surviving with those symptoms for the past 5 years and probably some outdoor stuff will do no harm.

I had to order a trekking backpack and trekking shoes which I don’t own. My luggage is split:

Personal Stuff: Everything I need while we seek for the location of the CHT base

  • Sleeping Bag
  • Trekking Shoes
  • Trekking Backpack
  • Camelbak
  • Clothes including Rain Coat
  • Regular Shoes
  • Power Banks, Laptop
  • Cat Ears and Skirt (yes, I love to wear those)
  • Sun Protection
  • Sun glasses and replacement glasses
  • Towel and washcloth
  • Power Banks
  • Mobile Phone and replacement phone
  • Medicine
  • Paracord
  • Hat
  • Camera + Charger to document stuff
  • Pillow
  • Flashlight and Headlamp

Stuff I can put into storage and fetch later when needed for setting up the base

  • 20W+40W Solar Cells
  • Charge Controller
  • Lead-Acid Batteries (if possible to transport by plane)
  • 12V to 230V Inverter
  • Unifi UAP and Unifi EdgeRouter Lite
  • Mechanical Tools like Screwdrivers
  • Cables for wiring up the solar cells, Wago Clamps
  • Spade
  • Replacement notebook
  • Multimeter, Wire strippers, pliers etc
  • Raspberry Pi
  • Network Cables
  • Soldering Iron, Soldering Wire
  • LED Lighting
  • Duct Tape
  • Alligator Clips


David confirmed that they’ll pick me up at the airport. Sounds like quite an adventure, but I’m optimistic that things will go nice. My bus from Berlin is leaving tomorrow morning. Hope I didn’t forgot to include anything important to this list. I always carry my ID and stuff with me, so no, that’s not included to the list.

Stay tuned!

Hacking and Living on Lanzarote – Day -5

I’m going to Lanzarote for working, hacking and a hopefully life-changing experience. If you’re following me on Twitter, you probably know about the awkward situation I’m in. I suffer from depression, I have left my family and I’m semi-homeless since two months and staying with friends since then. I had much time to think about my situation and came to several conclusions. I’m not going to list them except for one:

Don’t do what logic and society dictates – do what feels right.

I’ve listened to too many people giving too many false advices, simply because they believe that their lifestyle fits me. I mostly followed their advice without using my own brain. And believe me – that felt very very wrong. I was raised to follow other peoples advice, and I’m changing that since 2010 – since I joined RaumZeitLabor. I learned to accept that I am an individual, a thinker, maker and hacker. I also learned that I need to ask for help and to communicate with people to find creative solutions to problems.

As it’s hard to host people for extended periods of time, I have to move out of my hosts in Berlin. One solution would be to continue couchsurfing, but thanks to Sam, I learned about projects which hosts hackers to hack, work and colaborate on projects and get new views on life and the future of humanity.

One of those projects is and the CHT, who hosts a hacker community on Lanzarote. The upcoming season consists of building up an entire community, preferably off-the-grid with own power generators and a water treatment plant. This might sound quite as an adventure, and you’re right: It will be. But I’m not scared anymore, and I want to learn on how to deal with new situations and challenges.

Right now I’m looking for flights and planning what I need to bring, including medication, clothes, solar panels and inverters etc. The flight costs somewhere between 60€ and 100€. The cost for CHT is estimated to be around 400€ per month, which can probably be reduced. If you are able to financially support the project, please donate here.

Stay tuned for hopefully regular updates.

OXID Rants

Today I had a major outage in an OXID-based shop system. The reason is unknown; it did resolve “itself” as quickly as it appeared, leaving behind an almost 3 hour downtime of the system. I assume that it’s a combination of their odd caching, and during debugging what went wrong, I took some notes which I eventually wrote down in this blog entry.

OXID, why do you disable modules without any visual indication on the modules list?

OXID shows that modules are enabled, but some aren’t. Nothing in the error logs. No information on the GUI. After an hour of digging into the code, I found out that there’s a configuration entry in the OXCONFIG table (of course, crypted see below) which holds a serialized PHP array of disabled modules (“adisabledmodules”). I do not know at this point where this array is filled, but if it is, modules are silently ignored – and the worst thing: They are shown as if they are enabled.

OXID, why don’t you give any hints why a module can’t be enabled?

If OXID fails to enable a module, it does so silently. At least, this time you actually see that the module is disabled again, but you get no clue why.

OXID, why you store your config encrypted in the database?

OXID uses DECODE() and ENCODE() with a public known key to store data in the OXCONFIG table. This is next to useless and only makes maintenance harder. The key is actually the same for each installation. Of course, one could change the key, but this isn’t documented. Additionally, some contents of the OXCONFIG table are stored as temporary, unencrypted data in the tmp folder anyways.

OXID, why do you use a custom class extension system?

OXID uses a custom class extension system. Probably to emulate some kind of multiple inheritance. In theory, this doesn’t sound too bad, but in practice, this gives headaches, because it is implemented poorly.

Class names are mangled to lower case in some places, but not in others, causing all sorts of problems, combined with too much or simply wrong caching mechanisms. One needs to add their class extensions into a file called “metadata.php”, which looks like this:

Don’t ever change the case of _any_ class name. Here’s where the inconsistency begins: The actual PHP class name is “Thankyou”. Most modules so far use “thankyou” as class identifier for the “extend” portion of the array. If you’d use “Thankyou” as identifier, you’d mess up the whole system, resulting in “method not found” errors. And if you did that once, it gets cached in the system, and you have no chance to revert this unless you manually delete the information from the OXCONFIG table.


When I first started out with OXID, it didn’t seem too bad as a shop system: They got unit tests and a wide range of modules. Some of them are available as purchase-only variants, which is okay.

However, the quality of the whole OXID infrastructure is a big problem. It uses smarty templates all over the place, even in their admin backend. Modules assume that they are the only one who extend a template, which is often not the case (example: List headers). There’s no documentation on where you should extend functionality. There’s no overall picture of how the business logic works. You can even purchase two modules, which change the business logic.

The lack of technical documentation is a big no-go. Did you knew that database properties are mapped to an object’s tablename__fieldname property? If you want to retrieve an order’s order date, you need to use:

This is neither documented within the oxBase class nor on their OXIDForge Website. If you decide to step into OXID development, be aware that you’ll be on your own – forums aren’t too much help, and expect to read lots of (odd), undocumented code.