There are two problems, lack of list(,) when unpacking and 32 bit overflow if the pokemon is nicknamed. You could temporarly unset the nickname flag by temporarly masking byte 0x3B with 0x7F and using your code, or proceed by 16-bit words, for instance for the HP IV use:
$newIV = $row['HPIV'];
list(,$i) = unpack("v", substr($q,0x38,2)); // HP, Attack, Def
$i &= 0xFFE0; // Clear HP IV
$i |= ($newIV & 0x1F) << 0; // Set new HP IV
$q = substr($q,0,0x38).pack("v",$i).substr($q,0x3A);
Of course for speed you'll need 0x39-0x3A, and for SA/SDef 0x3A-0x3B... for the other solution:
$n = ord($q[0x3B]);
$nicknamed = $n>>7;
$q[0x3B] = chr($n & 0x7F);
// ... Your pastebin code fixed with list(,) before unpacks
if($nicknamed) $q[0x3B]=chr(ord($q[0x3B]) | 0x80);
Third and best solution is use a 64 bit OS.