[英]How to save an IP address as binary using Eloquent and PostgreSQL?
首先,這是我獲得信息的SO問題+答案-laravel 4將ip地址保存到模型中 。
因此,我的表可能有數以百萬計的行,因此,為了保持較低的存儲量,我選擇了選項2-使用模式構建器的binary()列,並在Eloquents的訪問器/更改器的幫助下將IP轉換/存儲為二進制。
這是我的桌子:
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錯誤的網關錯誤。
好。 因此,我認為Eloquent / PostgreSQL必須在傳遞二進制數據時不能很好地配合使用。
我做了一些搜索,發現了pg_unescape_bytea()
和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 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數據類型概述頁面供您進一步參考。
也就是說,其他人可能會偶然發現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),而大型數據對象在服務器上需要大量內存(甚至在移動設備上可能會出現問題),那么這可能是個問題。沒有交換的設備)。 在這種情況下,您應該在服務器和客戶端上使用流,並僅在您真正需要的客戶端上獲取數據。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.