Mittwoch, 19. April 2017

Using PHP-FPM + Apache on Ubuntu after upgrading to 17.04 (Zesty Zapus)

Up until Ubuntu 16.10 I used PHP-FPM on Apache via mod_fastcgi module. The setup was similar to what you can find in this tutorial: https://www.howtoforge.com/tutorial/apache-with-php-fpm-on-ubuntu-16-04/
With 17.04 the package mod_fastcgi was dropped from repository, as it seems to be unsupported since some time.

The way to go is switching to mod_proxy_fcgi, which seems to come preinstalled with the apache2 package and is just deactivated by default.

sudo a2enmod proxy_fcgi

I used PHP-FPM via socket and wanted to continue using it the same way, so I edited my site conf to add following lines within the VirtualHost configuration node:

<IfModule mod_proxy_fcgi.c>
    <Proxy "fcgi://localhost/" enablereuse=on max=10>
    </Proxy>
    <FilesMatch "\.php$">
        <If "-f %{REQUEST_FILENAME}">
            SetHandler "proxy:unix:/run/php/php7.0-fpm.sock|fcgi://localhost/"
        </If>
    </FilesMatch>
</IfModule> 

This was enough to make it run with the standard configuration. If you use a different socket for your vhost or do it via tcp with port, you would have to change the configuration accordingly. The official documentation of apache project for PHP-FPM lists the different configuration possibilities.

Mittwoch, 20. Juli 2016

ZF2 form validator translation

Zend Framework brings own translations with it. As of ZF 2.4 there are translations for Zend_Captcha and Zend_Validator. I wanted to use the latter in most easy way possible, without any hard magic or too much additional coding.

One possibility would have been adding the translations to module.config.php right after the inclusion of mo files, which are there by default with the Zend Skeleton Application.

    'translator' => array(
        'locale' => 'en_US',
        'translation_file_patterns' => array(
            array(
                'type'     => 'gettext',
                'base_dir' => __DIR__ . '/../language',
                'pattern'  => '%s.mo',
            ),
        ),
    ),

I decided to go with small modification of my  Module.php where only few lines have to be added.

<?php

namespace Application;

/* all your other use imports */
use Zend\Validator\AbstractValidator;

class Module
{
    public function onBootstrap(MvcEvent $e)
    {
        /* all your other function logic*

        // Dynamically adding translation files, which are bundled with ZF. (Zend_Captcha + Zend_Validate)
        // Caveats:
        // - Path to files could change in future releases, so this should be checked adjusted accordingly, when upgrading.
        // - No (expensive) file checking is done and if the file doesn't exist, an error message could be thrown, when translator tries to include inexistent file.
        $translator = $e->getApplication()->getServiceManager()->get('translator');
        $localePrimary = \Locale::getPrimaryLanguage($translator->getLocale());
        $translator->addTranslationFile(
            'phpArray',
            './vendor/zendframework/zendframework/resources/languages/' . $localePrimary . '/Zend_Captcha.php',
            'default',
            $translator->getLocale()
        );
        $translator->addTranslationFile(
            'phpArray',
            './vendor/zendframework/zendframework/resources/languages/' . $localePrimary . '/Zend_Validate.php',
            'default',
            $translator->getLocale()
        );
        AbstractValidator::setDefaultTranslator($translator);
    }

    /* all your other functions */
}

This is enough and the Zend translation files will be loaded by the translator object. It's also important to set it as default translator to all validators with the last lines, so all instantiated implementations will use the correct language from the beginning. The paths are correct for ZF 2.4, for any other releases they might be different and would need to be adjusted accordingly. I use Locale::getPrimaryLanguage to extract just the two letter locale code used by Zend translation files. This way you could work properly without any special with multiple sublocales like en_US and en_GB, de_DE and de_AT simultaneously without any additional hacks.

If you are already using Zend\Cache with translator, don't be as dumb as me and flush the cache, else you'll search for a long time for the reason of the code to seemingly not work. :D


You don't have to do anything for multilingual sites when using Zend\Cache though. Translator caches every language with different key on the first use, if it doesn't find it in cache. So you would only have to flush the cache, if you change something in your translations. There is no concurrency problem with multiple languages in use.

Sonntag, 17. Juli 2016

About ZF2, Bootstrap, jQuery UI, Modernizr and the case of missing date input field in Firefox

Recently I started to port an older project of mine, which I wrote years ago with Zend Framework 1 to the current stable and LTS branch of Zend Framework 2.4. In the course of this I'm learning the new code guidelines and to better separate the logic between the different layers of MVC.
Zend Framework 1 relied on Dojo Toolkit to have modern controls in form, this was mostly JavaScript workaround for missing features of HTML4. ZF2 on the other hand offers support for the newer HTML5 form controls. When I came to the date type input field, I learnt, that as of Firefox 47 this isn't supported yet.

input type date field as rendered by Firefox 47

And while the control looks good in Chrome, where I have native support and can use built-in calendar widget, in Firefox it's rendered like the plain input field of type text with no additional possibility to control, what the user types in, in which format and how to work around the different localised date formats used around the world.

input type date field as rendered by Chrome 51 with German locale
I already knew the Datepicker from jQuery UI project. So what I needed was some neat library, which could detect, if I use a browser, which does or doesn't properly support the date input field and optionally some Bootstrap theme for jQuery UI.
The browser ability detection seems to be implemented pretty well by Modernizr library. It has many different features, you can compile into the library, but only one special is of interest in this case: Form input types. Then you build it, you get a file called modernizr-custom.js, save it, we'll need it later.

There is also a Bootstrap theme for jQuery UI, which isn't officially up-to-date according to the version number, but the datepicker looks good with it.

As for the logical problem we not only need just the datepicker, as it will format the date beautiful, but this isn't usable for data processing, as in the backend and with proper HTML5 support the date sent by the form is in ISO 8601 format (YYYY-MM-DD). Luckily the datepicker supports filling of alternative fields with date in different format, so we need to create different and hidden input field, which will send the properly formatted date.

As I don't want to load those multiple JS and CSS files on every site, but only on sites with forms and I don't want to write the same code multiple times, the easiest way is a helper. In this example it is directly in the Application scope, so create the file /module/Application/src/Application/View/Helper/InputDateModernizrHelper.php and put the following content inside:

<?php

namespace Application\View\Helper;

use Zend\View\Helper\AbstractHelper;

class InputDateModernizrHelper extends AbstractHelper
{
    public function __invoke()
    {
        $this->view->headScript()->appendFile($this->view->basePath('/js/jquery-ui.js'));
        $this->view->headScript()->appendFile($this->view->basePath('/js/ui/i18n/datepicker-de.js');
        $this->view->headScript()->appendFile($this->view->basePath('/js/modernizr-custom.js'));
        $this->view->headLink()->appendStylesheet($this->view->basePath('/css/jquery-ui.css'));
        $this->view->headLink()->appendStylesheet($this->view->basePath('/css/jquery-ui-bootstrap-1.10.3.custom.css'));
        $this->view->headLink()->appendStylesheet($this->view->basePath('/css/jquery-ui-bootstrap-1.10.3.ie.css'), 'screen', 'lt IE 9');
        $this->view->headScript()->appendScript(
'$(document).ready(function() {
    if (!Modernizr.inputtypes.date) {
        $("input[type=date]").each(function(index) {
            var dateHelper = $(this).attr("name") + "_dateHelper_" + Math.random().toString(36).replace(/[^a-z]+/g, "");
            $(this).after("<input type=\'hidden\' id=\'" + dateHelper + "\' name=\'" + $(this).attr("name") + "\'>");
            $(this).attr("name", dateHelper);
            $(this).datepicker({
                altField: "#" + dateHelper,
                altFormat: "yy-mm-dd"
            });
        });
    }
});');
    }
}

To be able to easily use the helper, we have to register it in the file /module/Application/config/module.config.php by adding more or less one line of following code:

    'view_helpers' => array(
        'invokables'=> array(
            /* My other helpers... */
            'inputDateModernizrHelper' => 'Application\View\Helper\InputDateModernizrHelper',
        )
    ),

To use the helper in any view you just have to call following command:

$this->inputDateModernizrHelper();

And we are done! Of course other things aren't implemented like deleting the hidden value, if we change the content of the visible and formatted date field. The most easy way would be making the the visible field readonly and adding a small control to clear it and the invisible date field.

As of now, I'm content with this solution, but this is very hacked version. There is another interesting library, which uses so called polyfill techniques to detect unimplemented features and offer some JS replacement. It goes beyond simple detection and is more or less all-in-one package. The only caveat is that as far as I understand, it would only work properly for IE9 and newer and not below (at least the automatic detection could be buggy) and you need jQuery < v3. The magic library is called Webshim.
jQuery should be a big problem as v3 is fairly new and the old v1 branch is still supported with fixes, though it's more or less v2 branch with additional support for IE6, 7 and 8. If you don't have to support the legacy Windows XP (support for it ended on April 8th of 2014 unless you are crazy enough to hold on this system trying to get POSReady security updates or are actually paying for support), which runs only IE8 as the browser, you're good. Windows Vista is able to run IE9 and will receive support until April 11th of 2017, so you would run good with this combination.

P.S.
There is some compatibility layer called jQuery Migrate 3.0 plugin, which adds migration help and compatibility layer for deprecated APIs, so Webshim could also run with it perhaps.

Mittwoch, 16. April 2014

So now I spent several hours trying to fix missing MAC address on my old motherboard just to find out that almost everything was done right by me, just the EMS DOS driver was making problems.
The board was an old ASUS M3A-H/HDMI, which still works pretty good, but some years ago the network stopped working in Windows, it got correct IP configuration via DHCP, it could send packages but didn't receive any. On Linux everything worked ok. The problem was that the MAC address disappeared from BIOS when I flashed a new version as I found out today.
So my only solution, while I was using the motherboard on a regular basis, was to manually set the MAC address in Windows to the same as Linux was generating as the one generated by Windows wasn't working with my router. (Of course it still could be the case that Windows wasn't generating any and just showed some bullshit.)
Today I was setting up a new PC with older components and did a research which pointed me to the blog entry of trweb which described my problem and had some thoughts and a solution suggestion. I found the mentioned DMI236.EXE and tried it out by booting FreeDOS via an USB flash drive created with a very useful utility YUMI. I was sad to find out that DMI236 crashed with some cryptic error "Illegal Instruction occurred". The also mentioned AFUDOS.EXE (AMI BIOS flashing utility) didn't bring the solution. ASUS offered only a modified version without MAC setting options and the unmodified AFUDOS by AMI was telling me that my BIOS didn't support it. Hours later trying FreeDOS Live CD, modified Live CD with some other settings and more I stumbled across a thread which told me that the problem was occurring in combination of some DOS programs and EMS implementation of FreeDOS EMM386.EXE providing EMS and the solution was to just use XMS provided by HIMEM.SYS et voilà - DMI236 worked, set the MAC address and both Linux and Windows showed the correct address and worked without any quirks.
All at all it was a productive day and I had some fun going back to the ancient DOS days.

Donnerstag, 5. Dezember 2013

Delphi and the (still a little bit missing) ternary operator

One of the things I missed in Delphi is the ternary operator, that I learned to love and use in other programming languages. It helps saving lines of code and in most cases is more readable than the longer annotation. Look for example at the following example in C/C++/Java syntax:
if SomeBooleanVal {
  a = b;
} else {
  a = c;
}
SomeFunction(a);

There are several lines of code which could be just one easy readable line width the same meaning:
SomeFunction(SomeBooleanVal ? b : c);

Since Delphi 7 (or 6?) there is an IfThen function in StrUtils and Math lib supporting similar functionality for string, Integer, Int64 and Double data types.

So look at the following example for detailed code:
if SomeBooleanVal
  a := b
else
  a := c;
SomeFunction(a);

And now at the much shorter code:
SomeFunction(IfThen(SomeBooleanVal, b, c);

While it helps keeping the code simpler, it sill has its limitations. The function is only defined for four data types and you would have to write another function for every data type you need which is not one of the four. The other limitation is simply the fact that it is a function and not a compiler feature like in other languages so there is no laziness possible. If you submit something more complex as b and c parameters like d *10 - e / 5, both values are evaluated first and the result of them sent to the function which would return the correct result depending on the boolean value. In C only the needed of both values would be evaluated and assigned to the target variable.
Of course with today's machines it's not the most ugly loss of efficiency, it still shows some limitations of a language design.

Edit:
+Eric Grange pointed another simple case which IfThen can't handle:
a := IfThen(c<>0, b/c)

Because evaluation happens before check you will get division by zero if c is zero.

Mittwoch, 4. Dezember 2013

Delphi and missing Windows API functions

When I had to write a Windows service using Delphi 2010, which is possible thanks to WinSvc.pas, which is based on winsvc.h from Windows SDK, I found several functions just missing from the pascal unit. One of the functions I missed was ChangeServiceConfig2, which I could use to set extended service properties without fiddling with registry and setting some string and DWORD values.
I decided to go deep into the old SDKs to see what version the unit represents and was very surprised that it still had more or less the stand of Win9x line, though I'm not sure of WinME because I couldn't find it's SDK or advapi32.dll. While at least the function EnumServicesStatusEx was already in NT4.0 (but not in Win98FE), many new functions came with Win2k SDK (including ChangeServiceConfig2 which I intended to use) which was released in 2000. With Delphi support for WinXP (released in 2001) which is supported since Delphi 7 (released in 2002) they still didn't implement the new and missing WinAPI bindings and this seems to be still the situation as of today.

I decided to properly implement all the missing functions and structures of winsvc.h from Win2k SDK and so far have added extensions from WinXP SDK. (Here it's just the same as Win2k + two new constants) and currently I'm in the process of adding the extensions which came with Windows Vista, but this is WIP yet.

Because the might be several other API binding missing I decided to create a small project for this, so all the binding extensions can live in one central place. You will find the WIP source and the "stable" releases of the units here: https://github.com/rarog/winapi-for-delphi.

Dienstag, 26. November 2013

jQuery sticky sidebar plugin

For a small project I had to search for a new sticky sidebar plugin which would meet my needs. Previously I used the plugin made by p-m-p but it had some issues with not dealing with a position to stop and if the element was not fitting to screen it moved it below the site bottom edge, so the new edge was prolonged. A user could almost scroll into infinity.

Some days ago I found another sticky sidebar plugin made by Spoiled Milk which seems to have almost perfect functionality for my purposes, it can be configured pretty good. The only small issue I had I could circumvent by adding one line and modifying another line of code to be perfect for me. My problem was that the top edge of the element I wanted to be sticky wasn't just below a generic horizontal element but one of several in a vertical row with my element being the last, so it wasn't sufficient to just get the element above my sticky element as header and getting it's height like the plugin does it as of the time of this post being written, I have to add the top offset relative to the top edge of the document.

Search for the follwing line:
var breakingPoint1 = headerHeight + navHeight;

Replace it with the following two lines:
var headerTop = $(config.headerSelector).offset().top;
var breakingPoint1 = headerTop + headerHeight + navHeight;

Et voilà, it works as intended!