簡體   English   中英

如何使用Eloquent和PostgreSQL將IP地址保存為二進制文件?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM