First off, here's the SO question+answer where I got my information - laravel 4 saving ip address to model.
So my table will potentially have millions of row, therefore to keep storage low I opted for option 2 - using the Schema builder's binary() column and converting/storing IPs as binary with the help of Eloquents' accessors/mutators.
Here's my table:
Schema::create('logs', function ( Blueprint $table ) {
$table->increments('id');
$table->binary('ip_address'); // postgresql reports this column as BYTEA
$table->text('route');
$table->text('user_agent');
$table->timestamp('created_at');
});
The first problem I ran into was saving the IP address. I set an accessor/mutator on my model to convert the IP string into binary using inet_pton()
and inet_ntop()
. Example:
public function getIpAddressAttribute( $ip )
{
return inet_ntop( $ip );
}
public function setIpAddressAttribute( $ip )
{
$this->attributes['ip_address'] = inet_pton( $ip );
}
Trying to save an IP address resulted in the whole request failing - nginx would just return a 502 bad gateway error.
OK. So I figured it had to be something with Eloquent/PostgreSQL not playing well together while passing the binary data.
I did some searching and found the pg_escape_bytea()
and pg_unescape_bytea()
functions. I updated my model as follows:
public function getIpAddressAttribute( $ip )
{
return inet_ntop(pg_unescape_bytea( $ip ));
}
public function setIpAddressAttribute( $ip )
{
$this->attributes['ip_address'] = pg_escape_bytea(inet_pton( $ip ));
}
Now, I'm able to save an IP address without a hitch (at least, it doesn't throw any errors).
The new problem I'm experiencing is when I try to retrieve and display the IP. pg_unescape_bytea()
fails with pg_unescape_bytea() expects parameter 1 to be string, resource given
.
Odd. So I dd()
$ip in the accessor, the result is resource(4, stream)
. Is that expected? Or is Eloquent having trouble working with the column type?
I did some more searching and found it's possible that pg_unescape_bytea()
is not properly unescaping the data - https://bugs.php.net/bug.php?id=45964.
After much headbanging and hairpulling, it became apparent that I might be approaching this problem from the wrong direction, and need some fresh perspective.
So, what am I doing wrong? Should I be using Postgres' BIT VARYING
instead of BYTEA
by altering the column type --
DB::statement("ALTER TABLE logs ALTER COLUMN ip_address TYPE BIT VARYING(16) USING CAST(ip_address AS BIT VARYING(16))");`
-- Or am I merely misusing pg_escape_bytea / pg_unescape_bytea
?
All help is appreciated!