Category Archives: Software Development

This category contains all my posts about software development. Tutorials, solutions to problems I’ve met, interesting things I’ve stumbled over, code samples, stuff I don’t want to forget, et cetera.

Setting up GPG signing for Git/GitHub on Windows

What I did to get from working GPG to green and verified signatures for Git commits and tags on GitHub.

  1. Find the long id of the Signing key we want to use:
    🔶 $ gpg --edit-key alice
    gpg (GnuPG) 2.0.30; Copyright (C) 2015 Free Software Foundation, Inc.
    This is free software: you are free to change and redistribute it.
    There is NO WARRANTY, to the extent permitted by law.

    Secret key is available.

    pub  4096R/AA79CCAE  created: 2017-08-23  expires: never       usage: SC
                         trust: ultimate      validity: ultimate
    sub  4096R/62275E24  created: 2017-08-23  expires: never       usage: S 👈
    sub  4096R/4AEA9524  created: 2017-08-23  expires: never       usage: E
    [ultimate] (1). Alice Person (alice) <alice.person@example.com>
    [ultimate] (2)  Alice Person (alice) <alice@example.org>

    🔶 gpg> quit

    🔶 $ gpg --list-secret-keys --keyid-format LONG alice
    sec   4096R/8C0BBECBAA79CCAE 2017-08-23
    uid                          Alice Person (alice) <alice.person@example.com>
    uid                          Alice Person (alice) <alice@example.org>
    ssb   4096R/6ADB9D4262275E24 2017-08-23 👈
    ssb   4096R/33F2E1644AEA9524 2017-08-23

    Note: So in this case we want 6ADB9D4262275E24

  2. Configure git and (optionally) make it sign all commits by default:
    🔷 $ git config --global user.name "Alice Person"
    🔷 $ git config --global user.email "alice.person@example.com"
    🔶 $ git config --global user.signingkey "6ADB9D4262275E24"
    🔷 $ git config --global commit.gpgsign true
    🔷 $ git config --global push.gpgsign if-asked
    🔶 $ where gpg
    C:\Program Files (x86)\GNU\GnuPG\pub\gpg.exe
    🔶 $ git config --global gpg.program "C:/Program Files (x86)/GNU/GnuPG/pub/gpg.exe"

    Note: If repo specific, just skip --global and run the command in the repo instead.

Test it…

  1. Do a commit:
    🔷 $ git init gpg-test
    🔷 $ cd gpg-test
    🔷 $ touch file.txt
    🔶 $ git commit -a -m "Signed commit"

    You need a passphrase to unlock the secret key for
    user: "Alice Person (alice) <alice.person@example.com>"
    4096-bit RSA key, ID 62275E24, created 2017-08-23 (main key ID AA79CCAE)

    [master (root-commit) 2814856] Works...?
     1 file changed, 0 insertions(+), 0 deletions(-)
     create mode 100644 file.txt

    Note: One can also use the the -S option as alternative to using the commit.gpgsign true config, but as a forgetful person, I’d advice against that… Either set the config globally, or for the specific repo you need it for.

  2. Verify commit was signed:
    🔷 $ git log --show-signature
    commit 2814856365a07b3deb374f1337258102c06b77ef
    gpg: Signature made 08/23/17 06:18:50 W. Europe Daylight Time^M
    gpg:                using RSA key 6ADB9D4262275E24^M
    gpg: Good signature from "Alice Person (alice) <alice.person@example.com>" [ultimate]^M
    gpg:                 aka "Alice Person (alice) <alice@example.org>" [ultimate]^M
    Author: Alice Person <alice.person@example.com>
    Date:   Wed Aug 23 06:18:48 2017 +0200

        Signed commit
  3. Add a signed tag, using -s:
    🔶 $ git tag -s v1 -m "Signed tag"

    You need a passphrase to unlock the secret key for
    user: "Alice Person (alice) <alice.person@example.com>"
    4096-bit RSA key, ID 62275E24, created 2017-08-23 (main key ID AA79CCAE)

    Note: Unfortunately, unlike for commits, there is no tag.gpgsign true config as of writing, so to sign tags the -s option has to be remembered.

  4. Verify tag was signed:
    🔷 $ git tag -v v1
    gpg: Signature made 08/23/17 06:34:18 W. Europe Daylight Time
    gpg:                using RSA key 6ADB9D4262275E24
    gpg: Good signature from "Alice Person (alice) <alice.person@example.com>" [ultimate]
    gpg:                 aka "Alice Person (alice) <alice@example.org>" [ultimate]
    object 53e7f2e637eaf3c47b5dcad30b57be7b6829be02
    type commit
    tag v1
    tagger Alice Person <alice.person@example.com> 1503462856 +0200

    Signed tag

Add GPG key to GitHub

  1. Export the public key:
    🔶 $ gpg -a --export alice > public.txt
  2. Copy it.
  3. Go to GPG keys on GitHub.
  4. New GPG Key.
  5. Paste it.
  6. Add GPG Key.
  7. Pushed commits and tags should now look verified, as in this post: GPG signature verification

Sources: help.github.com, StackOverflow, git-scm.com

PHP: Unset all defined variables

foreach(get_defined_vars() as $k => $v)
    unset($$k);
unset($k, $v);

For example handy in this setting:

foreach($iterable as $item)
{
    extract($item);
    unset($item);

    // Define another variable, for only some of the items
    if($foo == 'bar')
        $x = 2;

    // Yield all defined vars
    yield get_defined_vars();

    // Cleanup, to prevent $x and other variables from
    // sticking around to the next iteration
    foreach(get_defined_vars() as $k => $v)
        unset($$k);
    unset($k, $v);
}

PHP: Pathable RecursiveIteratorIterator

Needed to recursively loop through a multi-dimensional array and print out each leaf-node with its full “path”.

For this I used an RecursiveArrayIterator for the array and a RecursiveIteratorIterator for the recursion. Thought I was home free because I had used a method called getSubpathname before, but turned out that was just something the RecursiveDirectoryIterator had…

So, had to grow my own… noting it here for others and the future:

class PathableRecursiveIteratorIterator
    extends RecursiveIteratorIterator
{
    /**
     * Gets the path to current node, i.e. each
     *   key "upwards", including self.
     *
     * @param null|string $glue Optional $glue for implode().
     *
     * @return array|string The keys, from root to self,
     *   as an array; or as a string if $glue is provided.
     */

    public function getPath($glue = null)
    {
        for($i = 0; $i < $this->getDepth(); $i++)
            $path[] = $this->getSubIterator($i)->key();

        $path[] = $this->key();

        return $glue !== null
            ? implode($glue, $path)
            : $path;
    }
}

Based upon: StackOverflow

Edit composer dependencies “inline” while developing

Have a PHP project, and want to re-use some classes in a new project. Moving them to their own repository and turning them into a Composer dependency is a clean way to do that. If hosted on GitHub/BitBucket, it’s even simply to be a bit more proper and fancy by publishing the package on Packagist with automatic updates based on git tags. However, if still heavily developing both the project and the dependency, the round trip through repo/packagist is a pain.

But today I discovered there’s an option called --prefer-source which seems to solve most of this pain. And here’s a basic note-to-self on how to get that to work…

0. Make sure dependency is a composer dependency

// Dependency composer.json
{
    "name": "my/package",
    "autoload":
    {
        "psr-4": {"": "src/"}
    }
}

1. Add dependency repo and package to root project

// Root project composer.json
{
    "repositories":
    [
        {"type": "vcs", "url": "https://github.com/username/my-project"}
    ],
    "require":
    {
        "my/project": "dev-master",
    }

2. Run update with –prefer-source

$ composer require my/package dev-master --prefer-source

We should now have the package downloaded and, more importantly, if you check ./vendor/my/package it should have the .git directory, meaning you can make immediately working changes there directly, and commit when you’re happy… Our other root project(s) depending on it should then get the update from the source repository after an easy composer update. 👍


Note: I’m a bit fuzzy on what composer does to keep track on whatever different happens through --prefer-source, and it’s an option for both composer install and composer update. For example, at first attempt, I tried to use composer update --prefer-source on a dependency that had already been downloaded, and the .git directory did not turn up, but if I just deleted the vendor directory for that package and then re-ran the command, then the .git was there.

So, feel free to comment if you have some light on that topic 😛🤓

PHP: Validating flexible/incomplete date time strings

Need to validate some datetime strings, that may or may not be incomplete. Might be for example just a year and a month, while the rest is unknown.

Noting it here in case I need it again. And in case someone else needs it, knows a more efficient/cleaner way, or sees a flaw…

function flexi_time($value): bool
{
    $valid = preg_match('/^(?<year>\d{4})(?:-(?<month>\d{2})(?:-(?<day>\d{2})(?:[ T](?<hour>\d{2}):(?<min>\d{2})(?::(?<sec>\d{2}))?)?)?)?$/', $value, $matches);
   
    if( ! $valid)
        return false;

    extract($matches);

    // Check month
    if($month ?? null AND ! between($month, 1, 12))
        return false;

    // Check date
    if($day ?? null AND ! checkdate($month, $day, $year))
        return false;

    // Check hour
    if($hour ?? null AND ! between($hour, 0, 23))
        return false;

    // Check minute
    if($min ?? null AND ! between($min, 0, 59))
        return false;

    // Check second
    if($sec ?? null AND ! between($sec, 0, 59))
        return false;

    return true;
}

function between($value, $min, $max): bool
{
    return $value >= $min && $value <= $max;
}

Test

$dates = [
    'foo', // Invalid
    '17', // Invalid
    '2017',
    '2017-01',
    '2017-13', // Invalid month
    '2017-01-17',
    '2017-02-31', // Invalid date
    '2017-01-17 20', // Invalid hour without minutes
    '2017-01-17 20:00',
    '2017-01-17T20:00', // Both space and T allowed as separator
    '2017-01-17 20:00:10',
    '2017-01-17 25:00:10', // Invalid hour
    '2017-01-17 20:70:70', // Invalid minute
    '2017-01-17 20:10:70', // Invalid second
];
print_r(array_filter($dates, 'flexi_time'));
Array
(
    [2] => 2017
    [3] => 2017-01
    [5] => 2017-01-17
    [8] => 2017-01-17 20:00
    [9] => 2017-01-17T20:00
    [10] => 2017-01-17 20:00:10
)

jQuery: How to extract a tag from an HTML response

Making a website, and using ajax for some things. Sometimes things fail and return custom error pages. I made them to be helpful, but since you can only see them in the browser developer console, they were a bit of a hassle to look at.

To see what the error was much easier, I figured I could just parse the returned HTML, extract the message I knew was there, and insert it into the page that way.

And you’d think the following would work fine:

$(document).ajaxError(function(event, jqxhr, settings, error)
{
    // Find the message in the response HTML
    var m = $(jqxhr.responseText)
        .find('#message');

    // Except .find() doesn't find anything

    // And we replace our DOM with nothing
    $('#content')
        .replaceWith(m);
});

But… No… Apparently, since the response was a complete HTML page, i.e. including html, head and body tags, jQuery was getting a bit tricked up when trying to parse it. Actually not sure if it’s jQuery or native browser parsing behind that’s causing it, but where there’s a will, there’s a way:

$(document).ajaxError(function(event, jqxhr, settings, error)
{
    // Find the inner HTML of the body tag
    var body = /<body.*>([\s\S]+)<\/body>/
        .exec(jqxhr.responseText);

    // Parse the HTML
    body = $.parseHTML(body[1])

    // Append the HTML to a non-special root tag
    body = $('<output>').append(body);

    // And *now* we can finally find our message
    var message = body.find('#message');

    // And add it to our DOM
    $('#content')
        .replaceWith(m);
});

¯\_(ツ)_/¯

PHP: preg_match_all_callback

There are several PCRE functions available, but today I looked for one that just wasn’t there: preg_match_all_callback().

Could’ve maybe used preg_replace_callback(), but felt wrong since I didn’t actually want to do any replacing. I just needed my function to be called for each match.

So I wrote it myself. Noting it here, in case I (or someone else) needs it again.

<?php
/**
 * Perform a global regular expression match
 * and calls the callback for each match.
 */

function preg_match_all_callback(
        string $pattern,
        string $subject,
        callable $callback)
{
    $r = preg_match_all($pattern, $subject, $matches, PREG_SET_ORDER);
    foreach($matches ?? [] as $match)
        $callback($match);
    return $r;
}

And, in case someone reads this post and knows it actually does exist… and if that someone is you, please do leave a comment!

And, yes, I could’ve just written those 3 lines where I needed them, but what’s the fun in that? And besides, the shorter the code where it counts, the easier what counts is to read.

Usage

preg_match_all_callback('/(\w)\w*/', 'Hello World', 'var_dump');
array (size=2)
  0 => string 'Hello' (length=5)
  1 => string 'H' (length=1)

array (size=2)
  0 => string 'World' (length=5)
  1 => string 'W' (length=1)