首先,这是我获得信息的 SO 问答 - laravel 4 saving ip address to model .
所以我的表可能有数百万行,因此为了保持低存储,我选择了选项 2 - 使用架构构建器的 binary() 列并在 Eloquents 的访问器/修改器的帮助下将 IP 转换/存储为二进制。
这是我的 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');
});
我遇到的第一个问题是保存 IP 地址。我在我的模型上设置了一个访问器/修改器,使用 inet_pton()
和 inet_ntop()
将 IP 字符串转换为二进制。示例:
public function getIpAddressAttribute( $ip )
{
return inet_ntop( $ip );
}
public function setIpAddressAttribute( $ip )
{
$this->attributes['ip_address'] = inet_pton( $ip );
}
尝试保存 IP 地址导致整个请求失败 - nginx 只会返回 502 bad gateway 错误。
好的。所以我想一定是 Eloquent/PostgreSQL 在传递二进制数据时不能很好地协同工作。
我做了一些搜索,找到了 pg_escape_bytea()
和 pg_unescape_bytea()
函数。我按如下方式更新了我的模型:
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 ));
}
现在,我可以毫不费力地保存 IP 地址(至少,它不会抛出任何错误)。
我遇到的新问题是当我尝试检索和显示 IP 时。 pg_unescape_bytea()
失败,pg_unescape_bytea() expects parameter 1 to be string, resource given
。
奇怪。所以我在访问器中dd()
$ip,结果是resource(4, stream)
。这是预期的吗?或者 Eloquent 在处理列类型时遇到问题?
我做了更多搜索,发现 pg_unescape_bytea()
可能没有正确地转义数据 - https://bugs.php.net/bug.php?id=45964 .
经过多次反复讨论后,很明显我可能从错误的方向处理这个问题,需要一些新的视角。
那么,我做错了什么?我是否应该通过更改列类型来使用 Postgres 的 BIT VARYING
而不是 BYTEA
--
DB::statement("ALTER TABLE logs ALTER COLUMN ip_address TYPE BIT VARYING(16) USING CAST(ip_address AS BIT VARYING(16))");`
-- 或者我只是误用了 pg_escape_bytea/pg_unescape_bytea
?
感谢所有帮助!
最佳答案
就像在对您的问题的评论中已经说过的那样:在您的特定情况下,您应该使用相应的 PostgreSQL 数据类型,处理起来会容易得多。与 MySQL 相比,PostgreSQL 中还有很多其他类型(如 JSON),有一个 PostgreSQL data type overview page以供进一步引用。
也就是说,其他人可能会偶然发现 bytea
字段的类似问题。你得到 Resource
而不是 string
的原因是 PostgreSQL 将 bytea
字段视为流。一种非常幼稚的方法是首先获取流然后返回数据:
public function getDataAttribute($value)
{
// This will kill your server under high load with large values.
$data = fgets($value);
return pg_unescape_bytea($data);
}
您可以想象,如果多个人试图获取大文件(目前为数百 MiB 或几 GiB),而大型数据对象需要服务器上的大量内存(这甚至可能导致没有交换的移动设备上的问题)。在这种情况下,您应该在服务器和客户端上使用流,并只在您真正需要的客户端上获取数据。
关于postgresql - 如何使用 Eloquent 和 PostgreSQL 将 IP 地址保存为二进制文件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29245221/