HKDF is itself built from HMAC, so your question strikes me as a false dilemma. If you have HMAC, HKDF Is just a handful of HMAC calls; you could just implement your own. Yes, I know that "don't roll your own" is top cryptographic advice, but compared to the things you're already proposing to do that you illustrate in your question, implementing your HKDF on your own is only a marginal increase in risk. Reading the RFC should help you convince yourself of that. Or you could consider this third-party library that implements HKDF for you already.
Not that there's anything obviously wrong with the way you're using HMAC, but I just don't think that the lack of HKDF in some versions of PHP is big enough of an obstacle to to ground that decision.
A more interesting observation is that what you're doing to compute
$ak is almost identical to a single-block application of HKDF-expand (the second half of HKDF, which is in fact two functions—read the RFC). What you are doing differs from that only because HKDF-expand appends a block counter byte to its
info parameter. If you change your subkey derivation lines to append the counter byte:
$ek = hash_hmac($ha, "e\x01", $k, true);
$ak = hash_hmac($ha, "a\x01", $k, true);
...then that is by definition the same as this (pseudocode because PHP doesn't seem to have an actual
$ek = hkdf_expand($ha, $k, $ha_output_size, "e");
$ak = hkdf_expand($ha, $k, $ha_output_size, "a");
$ha_output_size is the output size of the hash function that
$ha refers to.
The other, earlier half of HKDF is the HKDF-extract function, whose purpose is to take random inputs that are not directly suitable for use directly as cryptographic keys because they are biased, and output a master pseudorandom key ("PRK" in the RFC's terminology) that is suitable for direct use or further derivation. But PBKDF2 is already intended to produce output that is suitable for use as a pseudorandom key, so arguably you don't need the HKDF-extract step.
So what you're doing is, overall, already almost the same as what you might do with HKDF. That's an argument that could be used to either keep doing it your way (the lack of the counter byte isn't going to break your app compared to HKDF-expand) or to actually stick in that extra byte so you actually are using HKDF.