17

我正在尝试使用 Laravel 4 将用户 ip 地址保存到我的数据库中。我发现以下函数返回一个字符串

Request::getClientIp()

我将如何将其存储在我的模型中?只是一个字符串还是有更有效的方法?

$table->string('ip_address');
4

3 回答 3

54

选项 1:使用 VARCHAR(45) 列

考虑另一个 SO 问题中的讨论IPv6 地址的文本表示的最大长度?包含 IPv4 隧道功能时,IPv6 的最大长度为 45。

因此,更安全的迁移命令是:

$table->string('ip_address', 45);

优点:

  1. 该列是人类可读的。设置值或查询行查看时无需转换。

缺点:

  1. 它比选项 2 使用更多空间,实际上几乎是 3 倍。但除非你计划它有数百万行,否则我不会太担心。

选项 2:使用 BLOB 列

由于@euantorano 提供了存储在 mysql 数据库中的 IP 地址的链接,您可以将 IP 存储为二进制文件以节省一些空间。

最简单的答案是使用:

$table->binary('ip_address');

优点:

  1. 以二进制形式存储 IP 地址将为您节省一些空间。

缺点:

  1. 您需要先使用 PHP 的inet_pton()之类的东西将 IP 地址字符串转换为二进制。该列将无法直接读取,因为它以二进制格式存储。如果尝试直接查询,您将看到奇怪的字符或空白。您可能想看看我在下面的选项 3 中存储和检索 IP 地址的方式。

  2. Laravel 中的查询构建器,尽管方法被称为二进制,实际上会为你创建一个 BLOB 列BLOB 存储在表外,行缓冲区之外,这可能意味着性能较低。而且确实没有理由不使用 BINARY 列类型,因为我们知道 IP 地址对于 BLOB 来说并不长。


选项 3:使用 VARBINARY(16) 列

Laravel 的查询构建器为选项 2 中的示例生成一个 BLOB 列。如果您使用的是 MySQL,您将希望使用 VARBINARY(16) 而不是 BLOB 以获得更好的性能。

迁移脚本:

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');
    }
}

显然,上面唯一重要的部分是 DB::statement(...)。我们需要使用Taylor Otwell 建议的原始查询。随意按照自己的方式创建表格的其余部分。

从这里您可以使用 PHP 的inet_pton()inet_ntop()将 IP 地址字符串转换为二进制,反之亦然。

优点:

  1. 与选项 1 相比节省空间
  2. 与选项 2 相比,数据库性能更好

缺点:

  1. 与选项 2 一样,您需要手动在二进制字符串和人类可读字符串之间来回转换,或者将 Eloquent 模型与一对自定义访问器/突变器一起使用,我将在下面演示。

额外功劳:添加自定义 Eloquent 访问器/修改器(可选):

这是我发现 Eloquent 非常有用的地方。您可以为 Eloquent 模型设置自己的访问器/修改器,并且可以像往常一样通过模型的实例变量获取/设置。

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);
    }
}

现在,如果你这样做:

$log = new MyLog;
$log->ip_address = '192.168.0.1';
$log->save();

IP 地址将正确保存为二进制。你可以这样做:

$log = MyLog::find(1);
echo $log->ip_address;

它会回显 192.168.0.1。很有用!

于 2014-06-17T18:23:34.887 回答
1
$table->string('ip_address', 39); 

因为 IPv6 地址的最大长度是 39。

支持 IPv4,因为它的长度不超过 15。

于 2014-02-27T20:16:38.260 回答
0

来自@Unnawut。

如果要在同一字段中同时处理 ipv4 和 ipv6,则需要从 更改为binary(16)varbinary(16)

但是如果你只需要处理 ip v4 就可以了INT UNSIGNED

如果你只想处理 ip v6BINARY(16)

参考:MYSQL - 选择 IP v4/v6、inet_pton 和 bin2hex

参考 2:https ://stackoverflow.com/a/5133610/2126472

于 2014-08-15T04:28:39.653 回答