I\'m trying to save a user ip address to my database using Laravel 4. I found the following function which returns a string
Request::getClientIp()
$table->string('ip_address', 39);
Because the maximum length of an IPv6 address is 39.
IPv4 will be supported as it's length doesn't exceeds 15.
Option 1: Use VARCHAR(45) column
Considering the discussion in another SO question Maximum length of the textual representation of an IPv6 address?, the maximum length of IPv6 is 45 when including the IPv4 tunneling feature.
Thus, a safer migration command would be:
$table->string('ip_address', 45);
Pros:
Cons:
Option 2: Use BLOB column
As @euantorano provided the link to IP address storing in mysql database, you may store the IP as binary to save some space.
The simplest answer would be to use:
$table->binary('ip_address');
Pros:
Cons:
You will need to convert the IP address string to binary first using something like PHP's inet_pton(). The column will not be directly readable since it is stored in binary format. You will see weird characters or blank if tried to query it out directly. You may want to look at my way to store and retrieve the IP address in Option 3 below.
The query builder in Laravel, despite the method being called binary, will actually create a BLOB column for you. BLOB is stored off the table, out of the row buffer, which possibly means a lower performance. And there really isn't a reason not to use BINARY column type since we know IP addresses aren't that long for BLOB to be necessary.
Option 3: Use VARBINARY(16) column
Laravel's query builder produces a BLOB column for the example in Option 2. If you are using MySQL, you will want to use VARBINARY(16) instead of BLOB for better performance.
Migration script:
class CreateMyLogsTable extends Migration {
public function up()
{
Schema::create('my_logs', function(Blueprint $table) {
$table->increments('id');
});
DB::statement('ALTER TABLE `my_logs` ADD `ip_address` VARBINARY(16)');
}
public function down()
{
DB::statement('ALTER TABLE `my_logs` DROP COLUMN `ip_address`');
Schema::drop('my_logs');
}
}
Obviously the only important part above is the DB::statement(...). We need to use raw queries as Taylor Otwell suggested. Feel free to create the rest of the table your way.
From here you can use PHP's inet_pton() and inet_ntop() to convert the IP address strings to binary and vice versa.
Pros:
Cons:
Extra credit: Add custom Eloquent accessor/mutator (optional):
Here is where I find Eloquent really useful. You can set your own accessor/mutator to your Eloquent model and you can get/set via your model's instance variable as usual.
class MyLog extends Eloquent {
public $timestamps = false;
public function getIpAddressAttribute($value)
{
return inet_ntop($value);
}
public function setIpAddressAttribute($value)
{
$this->attributes['ip_address'] = inet_pton($value);
}
}
Now if you do:
$log = new MyLog;
$log->ip_address = '192.168.0.1';
$log->save();
The IP address will be saved as binary correctly. And you can do:
$log = MyLog::find(1);
echo $log->ip_address;
And it will echo out 192.168.0.1. Very useful!
From @Unnawut.
You need to change from binary(16)
to varbinary(16)
if you want to deal with both ipv4 and ipv6 in the same field.
But if you need to deal only ip v4 just INT UNSIGNED
If you want to deal only ip v6 BINARY(16)
ref: MYSQL - SELECT IP v4/v6, inet_pton & bin2hex
ref2: https://stackoverflow.com/a/5133610/2126472