141

私は分析ツールを構築しており、現在、ユーザー エージェントからユーザーの IP アドレス、ブラウザー、およびオペレーティング システムを取得できます。

Cookie やローカル ストレージを使用せずに同じユーザーを検出する可能性があるかどうか疑問に思っています。ここでコード例を期待していません。さらに調べる場所の簡単なヒントです。

同じコンピューター/デバイスの場合、クロスブラウザー互換性が必要になることを忘れていました。基本的に、私は実際にはユーザーではなく、デバイスの認識を求めています。

4

12 に答える 12

411

序章

私の理解が正しければ、一意の識別子を持っていないユーザーを特定する必要があるため、ランダム データを照合してそのユーザーを特定する必要があります。次の理由により、ユーザーの ID を確実に保存することはできません。

  • クッキーは削除できます
  • IPアドレス変更可能
  • ブラウザは変更可能
  • ブラウザのキャッシュが削除される可能性があります

Java アプレットまたは Com オブジェクトは、ハードウェア情報のハッシュを使用する簡単なソリューションでしたが、最近では、人々はセキュリティを非常に意識しているため、これらの種類のプログラムをシステムにインストールすることは困難です. これにより、Cookie やその他の同様のツールを使用できなくなります。

クッキーおよびその他の同様のツール

データ プロファイルを作成してから、確率テストを使用して見込みユーザーを特定することを検討してください。これに役立つプロファイルは、次のいくつかの組み合わせによって生成できます。

  1. IPアドレス
    • 実際の IP アドレス
    • プロキシ IP アドレス (ユーザーは同じプロキシを繰り返し使用することがよくあります)
  2. クッキー
  3. Web バグ (バグが修正されるため信頼性は低くなりますが、それでも有用です)
    • PDF バグ
    • フラッシュバグ
    • Java バグ
  4. ブラウザ
    • クリック トラッキング (多くのユーザーが、訪問のたびに同じ一連のページを訪問します)
    • ブラウザ フィンガー プリント - インストールされたプラグイン (多くの場合、人々はさまざまな、ややユニークなプラグイン セットを持っています)
    • キャッシュされた画像 (Cookie を削除しても、キャッシュされた画像はそのままにしておくことがあります)
    • ブロブの使用
    • URL (ブラウザの履歴または Cookie には、https://stackoverflow.com/users/1226894http://www.facebook.com/barackobama?fref=tsなどの URL に一意のユーザー ID が含まれる場合があります)
    • システム フォント検出(これはほとんど知られていませんが、多くの場合、一意の調号です)
  5. HTML5 & Javascript
    • HTML5 ローカルストレージ
    • HTML5 Geolocation API と逆ジオコーディング
    • アーキテクチャ、OS 言語、システム時間、画面解像度など
    • ネットワーク情報 API
    • バッテリーステータス API

私がリストした項目は、もちろん、ユーザーを一意に識別するためのいくつかの可能な方法にすぎません。他にもたくさんあります。

データ プロファイルを構築するためのこの一連のランダム データ要素を使用して、次は何をすればよいでしょうか?

次のステップは、いくつかのファジー ロジックを開発することです。さらに良いのは、人工ニューラル ネットワーク(ファジー ロジックを使用する) を開発することです。どちらの場合も、システムをトレーニングし、そのトレーニングをベイジアン推論と組み合わせて結果の精度を高めるという考え方です。

人工ニューラルネットワーク

PHP 用のNeuralMeshライブラリを使用すると、人工ニューラル ネットワークを生成できます。ベイジアン推論を実装するには、次のリンクを確認してください。

この時点で、次のように考えるかもしれません。

一見単純なタスクに、なぜこれほど多くの数学と論理が必要なのでしょうか?

基本的に、単純作業ではないので。あなたが達成しようとしているのは、実際にはPure Probabilityです。たとえば、次の既知のユーザーがあるとします。

User1 = A + B + C + D + G + K
User2 = C + D + I + J + K + F

次のデータを受け取った場合:

B + C + E + G + F + K

あなたが本質的に求めている質問は次のとおりです。

受信したデータ (B + C + E + G + F + K) が実際に User1 または User2 である確率は? そして、これらの 2 つの一致のうち、最も可能性が高いのはどれですか?

この質問に効果的に答えるには、頻度と確率の形式理解する必要があります。ここで詳細を説明するには多すぎるため (リンクを提供しているのはそのためです)、良い例は、症状の組み合わせを使用して可能性のある病気を特定するMedical Diagnosis Wizard Applicationです。

データ プロファイル (上記の例では B + C + E + G + F + K) を構成する一連のデータ ポイントを [症状] として、未知のユーザーを[病気] として考えてみてください。病気を特定することで、適切な治療法をさらに特定できます (このユーザーを User1 として扱います)。

明らかに、複数の症状が特定されている疾患は特定が容易です。実際、特定できる症状が多ければ多いほど、診断はより簡単で正確になります。

他の選択肢はありますか?

もちろん。別の方法として、独自の単純なスコアリング アルゴリズムを作成し、完全一致に基づくこともできます。これは確率ほど効率的ではありませんが、実装がより簡単になる場合があります。

例として、次の単純なスコア チャートを考えてみましょう。

+------------------------+--------------------+------------+
| | プロパティ | 重量 | 重要性 |
+------------------------+--------------------+------------+
| | 実際の IP アドレス | 60 | 5 |
| | 使用されたプロキシ IP アドレス | 40 | 4 |
| | HTTP クッキー | 80 | 8 |
| | セッション Cookie | 80 | 6 |
| | サードパーティ Cookie | 60 | 4 |
| | フラッシュクッキー | 90 | 7 |
| | PDF バグ | 20 | 1 |
| | フラッシュバグ | 20 | 1 |
| | Java バグ | 20 | 1 |
| | 頻繁なページ | 40 | 1 |
| | ブラウザの指紋 | 35 | 2 |
| | インストール済みプラグイン | 25 | 1 |
| | キャッシュされた画像 | 40 | 3 |
| | URL | 60 | 4 |
| | システム フォントの検出 | 70 | 4 |
| | ローカルストレージ | 90 | 8 |
| | 位置情報 | 70 | 6 |
| | AOLTR | 70 | 4 |
| | ネットワーク情報 API | 40 | 3 |
| | バッテリ ステータス API | 20 | 1 |
+------------------------+--------------------+------------+

特定のリクエストで収集できる各情報について、関連するスコアを付与し、重要度を使用してスコアが同じ場合に競合を解決します。

コンセプトの証明

簡単な概念実証については、Perceptronをご覧ください。パーセプトロンは、パターン認識アプリケーションで一般的に使用されるRNA モデルです。それを完全に実装する古いPHP クラスもありますが、目的に合わせて変更する必要があるでしょう。

優れたツールであるにもかかわらず、パーセプトロンは依然として複数の結果 (可能な一致) を返すことができるため、スコアと差異の比較を使用すると、これらの一致の中から最適なものを特定するのに役立ちます。

仮定

  • 各ユーザーに関するすべての可能な情報 (IP、Cookie など) を保存します。
  • 結果が完全一致の場合、スコアを 1 増やします
  • 結果が完全一致でない場合、スコアを 1 減らします

期待

  1. RNA ラベルの生成
  2. データベースをエミュレートするランダム ユーザーを生成する
  3. 不明なユーザーを 1 人生成する
  4. 未知のユーザー RNA と値の生成
  5. システムは RNA 情報をマージし、パーセプトロンに教えます。
  6. パーセプトロンをトレーニングした後、システムには一連の重み付けがあります
  7. これで不明なユーザーのパターンをテストできるようになり、パーセプトロンが結果セットを生成します。
  8. すべての肯定的な一致を保存する
  9. 一致を最初にスコアで並べ替え、次に差で並べ替えます (上記のとおり)。
  10. 最も近い 2 つの一致を出力するか、一致が見つからない場合は空の結果を出力します

概念実証のコード

$features = array(
    'Real IP address' => .5,
    'Used proxy IP address' => .4,
    'HTTP Cookies' => .9,
    'Session Cookies' => .6,
    '3rd Party Cookies' => .6,
    'Flash Cookies' => .7,
    'PDF Bug' => .2,
    'Flash Bug' => .2,
    'Java Bug' => .2,
    'Frequent Pages' => .3,
    'Browsers Finger Print' => .3,
    'Installed Plugins' => .2,
    'URL' => .5,
    'Cached PNG' => .4,
    'System Fonts Detection' => .6,
    'Localstorage' => .8,
    'Geolocation' => .6,
    'AOLTR' => .4,
    'Network Information API' => .3,
    'Battery Status API' => .2
);

// Get RNA Lables
$labels = array();
$n = 1;
foreach ($features as $k => $v) {
    $labels[$k] = "x" . $n;
    $n ++;
}

// Create Users
$users = array();
for($i = 0, $name = "A"; $i < 5; $i ++, $name ++) {
    $users[] = new Profile($name, $features);
}

// Generate Unknown User
$unknown = new Profile("Unknown", $features);

// Generate Unknown RNA
$unknownRNA = array(
    0 => array("o" => 1),
    1 => array("o" => - 1)
);

// Create RNA Values
foreach ($unknown->data as $item => $point) {
    $unknownRNA[0][$labels[$item]] = $point;
    $unknownRNA[1][$labels[$item]] = (- 1 * $point);
}

// Start Perception Class
$perceptron = new Perceptron();

// Train Results
$trainResult = $perceptron->train($unknownRNA, 1, 1);

// Find matches
foreach ($users as $name => &$profile) {
    // Use shorter labels
    $data = array_combine($labels, $profile->data);
    if ($perceptron->testCase($data, $trainResult) == true) {
        $score = $diff = 0;

        // Determing the score and diffrennce
        foreach ($unknown->data as $item => $found) {
            if ($unknown->data[$item] === $profile->data[$item]) {
                if ($profile->data[$item] > 0) {
                    $score += $features[$item];
                } else {
                    $diff += $features[$item];
                }
            }
        }
        // Ser score and diff
        $profile->setScore($score, $diff);
        $matchs[] = $profile;
    }
}

// Sort bases on score and Output
if (count($matchs) > 1) {
    usort($matchs, function ($a, $b) {
        // If score is the same use diffrence
        if ($a->score == $b->score) {
            // Lower the diffrence the better
            return $a->diff == $b->diff ? 0 : ($a->diff > $b->diff ? 1 : - 1);
        }
        // The higher the score the better
        return $a->score > $b->score ? - 1 : 1;
    });

    echo "<br />Possible Match ", implode(",", array_slice(array_map(function ($v) {
        return sprintf(" %s (%0.4f|%0.4f) ", $v->name, $v->score,$v->diff);
    }, $matchs), 0, 2));
} else {
    echo "<br />No match Found ";
}

出力:

Possible Match D (0.7416|0.16853),C (0.5393|0.2809)

"D" の Print_r:

echo "<pre>";
print_r($matchs[0]);


Profile Object(
    [name] => D
    [data] => Array (
        [Real IP address] => -1
        [Used proxy IP address] => -1
        [HTTP Cookies] => 1
        [Session Cookies] => 1
        [3rd Party Cookies] => 1
        [Flash Cookies] => 1
        [PDF Bug] => 1
        [Flash Bug] => 1
        [Java Bug] => -1
        [Frequent Pages] => 1
        [Browsers Finger Print] => -1
        [Installed Plugins] => 1
        [URL] => -1
        [Cached PNG] => 1
        [System Fonts Detection] => 1
        [Localstorage] => -1
        [Geolocation] => -1
        [AOLTR] => 1
        [Network Information API] => -1
        [Battery Status API] => -1
    )
    [score] => 0.74157303370787
    [diff] => 0.1685393258427
    [base] => 8.9
)

Debug = true の場合、Input (Sensor & Desired)、Initial Weights、Output (Sensor、Sum、Network)、Error、Correction、および Final Weightsを確認できます。

+----+----+----+----+----+----+----+----+----+----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+------+-----+----+---------+---------+---------+---------+---------+---------+---------+---------+---------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----+----+----+----+----+----+----+----+----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----------+
| o  | x1 | x2 | x3 | x4 | x5 | x6 | x7 | x8 | x9 | x10 | x11 | x12 | x13 | x14 | x15 | x16 | x17 | x18 | x19 | x20 | Bias | Yin | Y  | deltaW1 | deltaW2 | deltaW3 | deltaW4 | deltaW5 | deltaW6 | deltaW7 | deltaW8 | deltaW9 | deltaW10 | deltaW11 | deltaW12 | deltaW13 | deltaW14 | deltaW15 | deltaW16 | deltaW17 | deltaW18 | deltaW19 | deltaW20 | W1 | W2 | W3 | W4 | W5 | W6 | W7 | W8 | W9 | W10 | W11 | W12 | W13 | W14 | W15 | W16 | W17 | W18 | W19 | W20 | deltaBias |
+----+----+----+----+----+----+----+----+----+----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+------+-----+----+---------+---------+---------+---------+---------+---------+---------+---------+---------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----+----+----+----+----+----+----+----+----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----------+
| 1  | 1  | -1 | -1 | -1 | -1 | -1 | -1 | 1  | 1  | 1   | 1   | 1   | 1   | 1   | -1  | -1  | -1  | -1  | 1   | 1   | 1    | 0   | -1 | 0       | -1      | -1      | -1      | -1      | -1      | -1      | 1       | 1       | 1        | 1        | 1        | 1        | 1        | -1       | -1       | -1       | -1       | 1        | 1        | 0  | -1 | -1 | -1 | -1 | -1 | -1 | 1  | 1  | 1   | 1   | 1   | 1   | 1   | -1  | -1  | -1  | -1  | 1   | 1   | 1         |
| -1 | -1 | 1  | 1  | 1  | 1  | 1  | 1  | -1 | -1 | -1  | -1  | -1  | -1  | -1  | 1   | 1   | 1   | 1   | -1  | -1  | 1    | -19 | -1 | 0       | 0       | 0       | 0       | 0       | 0       | 0       | 0       | 0       | 0        | 0        | 0        | 0        | 0        | 0        | 0        | 0        | 0        | 0        | 0        | 0  | -1 | -1 | -1 | -1 | -1 | -1 | 1  | 1  | 1   | 1   | 1   | 1   | 1   | -1  | -1  | -1  | -1  | 1   | 1   | 1         |
| -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | --  | --  | --  | --  | --  | --  | --  | --  | --  | --  | --  | --   | --  | -- | --      | --      | --      | --      | --      | --      | --      | --      | --      | --       | --       | --       | --       | --       | --       | --       | --       | --       | --       | --       | -- | -- | -- | -- | -- | -- | -- | -- | -- | --  | --  | --  | --  | --  | --  | --  | --  | --  | --  | --  | --        |
| 1  | 1  | -1 | -1 | -1 | -1 | -1 | -1 | 1  | 1  | 1   | 1   | 1   | 1   | 1   | -1  | -1  | -1  | -1  | 1   | 1   | 1    | 19  | 1  | 0       | 0       | 0       | 0       | 0       | 0       | 0       | 0       | 0       | 0        | 0        | 0        | 0        | 0        | 0        | 0        | 0        | 0        | 0        | 0        | 0  | -1 | -1 | -1 | -1 | -1 | -1 | 1  | 1  | 1   | 1   | 1   | 1   | 1   | -1  | -1  | -1  | -1  | 1   | 1   | 1         |
| -1 | -1 | 1  | 1  | 1  | 1  | 1  | 1  | -1 | -1 | -1  | -1  | -1  | -1  | -1  | 1   | 1   | 1   | 1   | -1  | -1  | 1    | -19 | -1 | 0       | 0       | 0       | 0       | 0       | 0       | 0       | 0       | 0       | 0        | 0        | 0        | 0        | 0        | 0        | 0        | 0        | 0        | 0        | 0        | 0  | -1 | -1 | -1 | -1 | -1 | -1 | 1  | 1  | 1   | 1   | 1   | 1   | 1   | -1  | -1  | -1  | -1  | 1   | 1   | 1         |
| -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | --  | --  | --  | --  | --  | --  | --  | --  | --  | --  | --  | --   | --  | -- | --      | --      | --      | --      | --      | --      | --      | --      | --      | --       | --       | --       | --       | --       | --       | --       | --       | --       | --       | --       | -- | -- | -- | -- | -- | -- | -- | -- | -- | --  | --  | --  | --  | --  | --  | --  | --  | --  | --  | --  | --        |
+----+----+----+----+----+----+----+----+----+----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+------+-----+----+---------+---------+---------+---------+---------+---------+---------+---------+---------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----+----+----+----+----+----+----+----+----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----------+

x1 から x20 は、コードによって変換された機能を表します。

// Get RNA Labels
$labels = array();
$n = 1;
foreach ( $features as $k => $v ) {
    $labels[$k] = "x" . $n;
    $n ++;
}

オンラインデモはこちら

使用クラス:

class Profile {
    public $name, $data = array(), $score, $diff, $base;

    function __construct($name, array $importance) {
        $values = array(-1, 1); // Perception values
        $this->name = $name;
        foreach ($importance as $item => $point) {
            // Generate Random true/false for real Items
            $this->data[$item] = $values[mt_rand(0, 1)];
        }
        $this->base = array_sum($importance);
    }

    public function setScore($score, $diff) {
        $this->score = $score / $this->base;
        $this->diff = $diff / $this->base;
    }
}

修正パーセプトロン クラス

class Perceptron {
    private $w = array();
    private $dw = array();
    public $debug = false;

    private function initialize($colums) {
        // Initialize perceptron vars
        for($i = 1; $i <= $colums; $i ++) {
            // weighting vars
            $this->w[$i] = 0;
            $this->dw[$i] = 0;
        }
    }

    function train($input, $alpha, $teta) {
        $colums = count($input[0]) - 1;
        $weightCache = array_fill(1, $colums, 0);
        $checkpoints = array();
        $keepTrainning = true;

        // Initialize RNA vars
        $this->initialize(count($input[0]) - 1);
        $just_started = true;
        $totalRun = 0;
        $yin = 0;

        // Trains RNA until it gets stable
        while ($keepTrainning == true) {
            // Sweeps each row of the input subject
            foreach ($input as $row_counter => $row_data) {
                // Finds out the number of columns the input has
                $n_columns = count($row_data) - 1;

                // Calculates Yin
                $yin = 0;
                for($i = 1; $i <= $n_columns; $i ++) {
                    $yin += $row_data["x" . $i] * $weightCache[$i];
                }

                // Calculates Real Output
                $Y = ($yin <= 1) ? - 1 : 1;

                // Sweeps columns ...
                $checkpoints[$row_counter] = 0;
                for($i = 1; $i <= $n_columns; $i ++) {
                    /** DELTAS **/
                    // Is it the first row?
                    if ($just_started == true) {
                        $this->dw[$i] = $weightCache[$i];
                        $just_started = false;
                        // Found desired output?
                    } elseif ($Y == $row_data["o"]) {
                        $this->dw[$i] = 0;
                        // Calculates Delta Ws
                    } else {
                        $this->dw[$i] = $row_data["x" . $i] * $row_data["o"];
                    }

                    /** WEIGHTS **/
                    // Calculate Weights
                    $this->w[$i] = $this->dw[$i] + $weightCache[$i];
                    $weightCache[$i] = $this->w[$i];

                    /** CHECK-POINT **/
                    $checkpoints[$row_counter] += $this->w[$i];
                } // END - for

                foreach ($this->w as $index => $w_item) {
                    $debug_w["W" . $index] = $w_item;
                    $debug_dw["deltaW" . $index] = $this->dw[$index];
                }

                // Special for script debugging
                $debug_vars[] = array_merge($row_data, array(
                    "Bias" => 1,
                    "Yin" => $yin,
                    "Y" => $Y
                ), $debug_dw, $debug_w, array(
                    "deltaBias" => 1
                ));
            } // END - foreach

            // Special for script debugging
             $empty_data_row = array();
            for($i = 1; $i <= $n_columns; $i ++) {
                $empty_data_row["x" . $i] = "--";
                $empty_data_row["W" . $i] = "--";
                $empty_data_row["deltaW" . $i] = "--";
            }
            $debug_vars[] = array_merge($empty_data_row, array(
                "o" => "--",
                "Bias" => "--",
                "Yin" => "--",
                "Y" => "--",
                "deltaBias" => "--"
            ));

            // Counts training times
            $totalRun ++;

            // Now checks if the RNA is stable already
            $referer_value = end($checkpoints);
            // if all rows match the desired output ...
            $sum = array_sum($checkpoints);
            $n_rows = count($checkpoints);
            if ($totalRun > 1 && ($sum / $n_rows) == $referer_value) {
                $keepTrainning = false;
            }
        } // END - while

        // Prepares the final result
        $result = array();
        for($i = 1; $i <= $n_columns; $i ++) {
            $result["w" . $i] = $this->w[$i];
        }

        $this->debug($this->print_html_table($debug_vars));

        return $result;
    } // END - train
    function testCase($input, $results) {
        // Sweeps input columns
        $result = 0;
        $i = 1;
        foreach ($input as $column_value) {
            // Calculates teste Y
            $result += $results["w" . $i] * $column_value;
            $i ++;
        }
        // Checks in each class the test fits
        return ($result > 0) ? true : false;
    } // END - test_class

    // Returns the html code of a html table base on a hash array
    function print_html_table($array) {
        $html = "";
        $inner_html = "";
        $table_header_composed = false;
        $table_header = array();

        // Builds table contents
        foreach ($array as $array_item) {
            $inner_html .= "<tr>\n";
            foreach ( $array_item as $array_col_label => $array_col ) {
                $inner_html .= "<td>\n";
                $inner_html .= $array_col;
                $inner_html .= "</td>\n";

                if ($table_header_composed == false) {
                    $table_header[] = $array_col_label;
                }
            }
            $table_header_composed = true;
            $inner_html .= "</tr>\n";
        }

        // Builds full table
        $html = "<table border=1>\n";
        $html .= "<tr>\n";
        foreach ($table_header as $table_header_item) {
            $html .= "<td>\n";
            $html .= "<b>" . $table_header_item . "</b>";
            $html .= "</td>\n";
        }
        $html .= "</tr>\n";

        $html .= $inner_html . "</table>";

        return $html;
    } // END - print_html_table

    // Debug function
    function debug($message) {
        if ($this->debug == true) {
            echo "<b>DEBUG:</b> $message";
        }
    } // END - debug
} // END - class

結論

Unique Identifier を使用せずにユーザーを識別することは、単純な作業ではありません。それは、さまざまな方法でユーザーから収集できる十分な量のランダム データを収集することに依存しています。

人工ニューラル ネットワークを使用しないことを選択した場合でも、少なくとも優先順位と可能性を含む単純な確率マトリックスを使用することをお勧めします。上記のコードと例で十分に理解できることを願っています。

于 2013-04-20T13:38:12.253 に答える
29

この手法 (Cookie を使用せずに、または IP アドレスを使用せずに同じユーザーを検出する) は、ブラウザー フィンガープリンティングと呼ばれます。基本的に、可能な限りブラウザに関する情報としてクロールします。より良い結果は、javascript、flash、または java (インストールされている拡張機能、フォントなど) を使用して達成できます。その後、必要に応じて結果をハッシュして保存できます。

それは絶対確実ではありませんが、次のとおりです。

確認されたブラウザの 83.6% が一意のフィンガープリントを持っていました。Flash または Java が有効になっているユーザーの 94.2%。これには Cookie は含まれません。

より詳しい情報:

于 2013-04-18T20:32:38.593 に答える
4

キャッシュされた png を使用してこれを行うこともできますが、多少信頼性が低くなります (ブラウザによって動作が異なり、ユーザーがキャッシュをクリアすると失敗します) が、これはオプションです。

1: 一意のユーザー ID を 16 進文字列として格納するデータベースをセットアップします

2: ユーザー ID を生成する genUser.php (または任意の言語) ファイルを作成し、それを DB に格納してから、その 16 進文字列の値から True Color .png を作成し (各ピクセルは 4 バイトになります)、戻ります。それをブラウザに。content-type ヘッダーとキャッシュ ヘッダーを必ず設定してください。

3: HTML または JS で次のような画像を作成します<img id='user_id' src='genUser.php' />

4: その画像をキャンバスに描画しますctx.drawImage(document.getElementById('user_id'), 0, 0);

5: を使用してそのイメージのバイトを読み取り、ctx.getImageData整数を 16 進文字列に変換します。

6: これは、ユーザーのコンピューターにキャッシュされている一意のユーザー ID です。

于 2013-04-23T13:46:49.923 に答える
1

デバイス識別子を保存するために blob を作成する可能性があります...

欠点は、ブラウザがファイル システムにアクセスしてファイルを直接保存できないため、ユーザーが blob をダウンロードする必要があることです (ダウンロードを強制できます)。

参照:

https://www.inkling.com/read/javascript-definitive-guide-david-flanagan-6th/chapter-22/blobs

于 2013-04-23T18:49:05.163 に答える
0

信じられない、http://browserspy.dkがまだここで言及されていない! このサイトには、分類器の構築に使用できる多くの機能 (パターン認識の観点から) が記載されています。

もちろん、機能を評価するために、特にサポート ベクター マシンとlibsvmをお勧めします。

于 2014-06-20T13:42:32.860 に答える
0

非効率的ですが、望ましい結果が得られる可能性があるため、API を自分でポーリングすることをお勧めします。一定間隔でユーザー データを送信するバックグラウンド プロセスをクライアント側に配置します。API に送信するには、ユーザー ID が必要です。それを取得したら、その一意の識別子に関連付けられた情報を送信できます。

これにより、Cookie と localstorage が不要になります。

于 2013-04-22T19:39:08.090 に答える