Tag Archives: php

Increase code coverage successively

I often come across legacy projects that have a very low code coverage (or none at all). Getting such a project up to a high code coverage can be very frustrating as you will have a poor code coverage for a very long time.

So instead of generating an overall code coverage report with every pull request I tend to create a so called patch coverage report that checks how much of the patch is actually covered by tests.

Having something like that in place also allows me to force contributors to include tests for their newly contributed code. Which in turn successively improves the overall code coverage up to a level where I might be able to go for that instead of the patch coverage.

But how to implement that?

That’s not as complicated as it sounds. As Sebastian Bergmann already wrote a tool for that.

Enter phpcov

Using phpcov requires us to

  • first generate a diff against the last code-revision,
  • then generate a coverage-report via phpunit --coverage-php and
  • then run phpcov against those artefacts.

So it’s as complicated as

$ git diff HEAD^1 > /tmp/patch.txt
$ ./tools/phpunit --coverage-php /tmp/coverage.cov
$ ./tools/phpcov patch-coverage --path-prefix /path/to/project /tmp/coverage.cov /tmp/patch.txt

That’s it.

It will return a non-zero value when not all lines are covered and it will tell you which lines aren’t covered.

So add that to your automation to have it executed at whatever stage you like (I recommend in the CI-pipeline of your Pull-/Merge-Request and let that fail whenever the return code is non-zero)

Github Action

If you want to see a way to implement that in GitHub Actions, check out this gist.

Enums. With PHP < 8.1

Recently I had to build something where an Enum would have been perfect.

But…

The Challenge

It needed to run on PHP 8.0. Of course.

So what to do? I decided to build an Enum like thingy that I can easily upgrade into a real Enum once we are on PHP8.1 with that project.

Why not use a library for that? There are plenty of libraries on packagist that already provide you with the basics!

For one thing: I only needed one Enum. Not a multitude. And Adding a further dependency to make creating one enum easier that will (hopefully) converted into a “eral” enum in about half a year? That sounds bit like taking the sledgehammer to crack a nut.

And on the other hand it turned out that creating an enum from scratch isn’t rocket science.

Continue reading Enums. With PHP < 8.1

joind.in – a personal plea

Joind.in is a community driven project to give feedback to speakers at conferences and events.

And besides that it is a great ressource for all those that want to participate in the community. Not only as it’s an opensource project that everyone can help to make even better! But to provide feedback it also contains a list of almost every conference and event that is of any significance to the (PHP-)community.

And as the driving force underneath the hood of joind.in is a great API everyone interested can do a lot of cool things with the data no one has ever thought of.

To get the most out of joind.in (and therefore that API) some things should to be considered when creating or editing an event in joind.in. Some of these I’ll list here:

Continue reading joind.in – a personal plea

Create signed PDF-Files

Some days ago a friend of mine asked me how to create PDF-Receipts. Background is that – at least in Germany – you can replace printed receipts with digitally signed PDF-Files. The signature has to comply to certain legal standards to be able to replace the printed copy but the way is the same whether it’s a self-signed certificate or an official one.

For the start I wanted to see how to sign a PDF-Document created with TCPDF. At a later time I will also have a look at how to sign a PDF-File using the libraries supported by PDFlib.com.

Signing PDF-files with TCPDF requires you to have the private key and the certificate available via a stream-ressource. That excludes certificates and keys on a signature-card as long as you can not export them.

Creating a signed PDF-File using TCPDF is rather simple as you can see in this code-snippet:

$pdf = new TCPDF(PDF_PAGE_ORIENTATION, PDF_UNIT, PDF_PAGE_FORMAT, true, 'UTF-8', false);

// set certificate file
$certificate = 'file://' . __DIR__ . '/cert/certificate.crt';
$privateKey = 'file://' . __DIR__ . '/cert/privateKey.crt';
// set document signature
$pdf->setSignature($certificate, $privateKey, 'test1234', '', 1, array());

// Do some more stuff here like creating the actual PDF-File

//Close and output PDF document
$pdf->output('test.pdf', 'D');

That’s it.

The hard part now is for one thing creating the actual PDF-File.
And the more important one question was “Which certificate-key-thingy goes where”.

That was the one that took me most of the time. When using a self-signed certificate as described in the TCPDF-Example you can somehow use the given openSSL shell-lines to get somehow to a result. But I wanted to sign the document with a “qualified electonical signature” which takes some more steps.

What is a qualified electronical signature? It’S nothing else than any other digital signature from a certification authority. The only difference is, that it has been issued according to the german “Signaturgesetz” which means, that it is based on a qualified certificate and has been created using a certain approved PKI. As I am not a lawyer, this is simply my own description of a legal process which might be inaccurate or plain false. So do not take my word as legally authoritative. A list of issuers for qualified electronical signatures can be found at http://www.nrca-ds.de/ZDAliste.htm

As I do not posses such a qualified electronical signature (and there currently is no need for me to get one) I tried the whole stuff with a certificate I got myself from CA-Cert. As far as I know (but I will verify that one soon) you can export a qualified electronic signature into a format that can be used for these purposes.

The relevant parts are the following variables

$certificate
needs to point to a certificate file in PEM-Format. Thats a plaintext-file with —–BEGIN CERTIFICATE—– and —–END CERTIFICATE—– and some base64 encoded stuff in between.
$privateKey
needs to point to a private key file in binary PKCS7-Format. Those files normally end in something like ‘.p12’ or ‘.pfx’. To open this file you normally need a passphrase which you have to provide as third parameter to $pdf->setSignature.

Using that certificate and private key you can now sign your PDF-file.

Babylonic Apache SetEnv

The Mission

The other day I had a PHP-project based on the ZendFramework where I had to display different logos whether the project was viewd on the preview or on the live system.

Until now I always exchanged the images after puling the live data from the repository. Of course this was one step that sometimes was forgotten, sometimes the correct images where already in the repository so ther was no need to do it – -all in all it was rather anoying. Yes, you could say: “Automate processes that are always the same” but that is not the point today.

I had something different in mind.

For the ZendFramework I already set an environment variable “APPLICATION_ENV” that defined whether the server hosts a development or a production environment.

Why not use that information to display a logo according to the environment?

So I had either the option to call the logo via a PHP-Script that checks the environment variable and returns the correct image.

Or I could use the – already for ZendFramework available – mod_rewrite to do some rewriting voodoo.

The first option would have meant to write a complete PHP-Script and call that every time the logo is asked for. Somewhat much to do for a simple rewriting I thought.

The Quest

So I went for the second option. And it took me some time to get it up and running.

What happened: I took the documentation for mod_rewrite and went through it. I already had the following section in my VirtualHost-Config

SetEnv APPLICATION_ENV development

So for the directory with the logos in I created the following .htaccess-file (Yes, I could also put it into the servers config file…)

RewriteEngine on
RewriteCond %{ENV:APPLICATION_ENV} development [NC]
RewriteRule ^logo(?!-preview)(.*)\.png$   logo-preview$1.png [NC]

Fine I thought and tried that!

No Luck.

Didn’t work

Not after hours of debugging, reading blogposts and forum-entries and rewriting the code one or the other way.

No Luck at all

During these hours of searching the net I found that I wasn’t the only one having that problem, but mostly the solution was to set the environment variable in the Rewrite Engine as well as via SetEnv. But there had to be a different way.

And there was.

The Happy End

After hours I finaly found http://httpd.apache.org/docs/2.0/env.html and there was a paragraph headed “Some Caveats”.
Bingo! Thats It.

SetEnv is called after the mod_rewrite-calls. SetEnvIf before!

So thats the solution. Use SetEnvIf instead of SetEnv.

So I changed my VirtualHost-Config the following way

-  SetEnv APPPLICATION_ENV development
+  SetEnfIf HTTP "HTTP.*" APPLICATION_ENV=development

Yes It takes some performance, because APPLICATION_ENV is now set on every Request, but as long as static Environment variables are set after dynamic ones, that is an SEP to me.

The ZendFramework-Projects behavior does not change as the change is completely transparent to it. But reloading the log now suddenly showed the correct result!

The Polish

Well I thought, fine. But why not set the APPLICATION_ENV according to the called host-name? And therefore moving the SetEnfIf-call from the virtualServer to the projects htaccess-file? At least that’s where I think it belongs to, as it’s a project-specific setting.

So I removed the SetEnvIf-Line from the VirtualHost-Config and placed the following into the projects .htaccess-file.

<IfModule setenvif_module>
    SetEnvIf Host "\.?(preview|stage|staging|development|dev|local)\.?" APPLICATION_ENV=development
</IfModule>

As soon as one of preview, stage, staging, dev, development or local is a part of the hostname the APPLICATION_ENV-variable will be set to “development”.

One could now change that to the local environment by adding other names as well, but for me it is sufficient.