プログラムコピーカウンターまたは使用統計の収集

少し前に、1つのオフィスの注文を実行しました。 プロジェクトの本質は今のところ重要ではありません(それは企業システムに何らかの付属物であり、顧客にコンピューターに配置しました)。要件の1つは、アプリケーションがその使用に関するレポートを送信することでした。 そして簡単に言えば、彼らは彼らのプログラムが顧客の間でどれだけの需要があるかを知りたかったのです。 そして、この波で、私は質問をしました-しかし、実際、あなたはプログラムを書いて、それをあきらめ、良い手でそれを売りました、または単にインターネットにそれを掲示しました。 それでは、次は何ですか? 彼女を実際に見たユーザーは何人ですか?



プログラムが販売用の場合、購入したライセンスまたはキーによって購入者の数を簡単に計算できます-誰と。 ただし、無料の場合は問題が発生します。 オフサイトダウンロードの数(存在する場合)を考慮することは無意味です。 インターネットに何かが入ると、ウェアーズのリソースとトレントトラッカーの数が増え始めます。



ここに添付されているソリューションでは、このような詳細なレポートは提供されず、ソフトウェア統計サービスなどのデータはあまり収集されません(必要ありません)(ただし、正しく覚えていれば支払われます)。 しかし、プラスもあります。システムはいつでもニーズに合わせて仕上げることができます。



私はオリジナルのふりをしません。確かに似たようなものがすでに存在するので、私は特にそれを探しませんでした。 私は詳細に書き込もうとしましたが、それは学生の用語集のようにも見えました。 一般的に、誰かが役に立つと面白いかもしれません。



個性



それで、私たちのプログラムは世界中に広がりました。そして今、私たちはそれがどれほどグローバルであるかを知りたいです。 最初に、あるコピーを別のコピーと区別する方法を決定する必要があります。 最初に頭に浮かぶのはGUIDです。 たとえば、インストール中またはアプリケーションの最初の起動時に生成し、ファイルまたはレジストリに保存します。 このオプションの利点はシンプルであり、マイナスはインストーラーが起動するたびにGUIDが新しくなることです。 すなわち 貧しい仲間がシステム(または、より簡単に言えば、私たちのプログラム)を再インストールすると、過大評価された結果が得られます。 このようなソリューションは、実際のユーザー数ではなく、プログラムのインストール数を計算するのに適していますが、大まかな見積もりに使用することはまったく問題ありません。 GUIDは、たとえば次のように取得できます。



string guid = Guid.NewGuid().ToString(); Console.WriteLine("guid: {0}", guid);
      
      





プログラムのコピーをコンピューターハードウェアにバインドすると、より正確な結果が得られます。 ただし、ここでは、アップグレード(たとえば、HDDの交換)により、HardwareIDも変更されることに留意する必要があります。 したがって、データソースには「最も長く」存続するものを使用することをお勧めします。 マザーボードまたはプロセッサである可能性があります。 通常、コンピューターが完全に交換されると変更されます。 以下は、CPU IDとMotherBoard IDを抽出し、それらからmd5ハッシュを計算するコードです。



結果はすでに識別に使用できます。



ゲティド
 private static string GetHID() { string CPUid = string.Empty; string MtbId = string.Empty; string DiskId = string.Empty; string HID = string.Empty; ManagementObjectSearcher mos = new ManagementObjectSearcher(); //  mos.Query = new ObjectQuery("Select * From Win32_processor"); foreach (ManagementObject mo in mos.Get()) { try { CPUid = mo["ProcessorID"].ToString(); } catch { } } //   mos.Query = new ObjectQuery("SELECT * FROM Win32_BaseBoard"); foreach (ManagementObject mo in mos.Get()) { try { MtbId = mo["SerialNumber"].ToString(); } catch { } } //   ManagementObject dsk = new ManagementObject(@"win32_logicaldisk.deviceid=""C:"""); try { DiskId = dsk["VolumeSerialNumber"].ToString(); } catch { } Byte[] Bytes = Encoding.ASCII.GetBytes(CPUid + MtbId + DiskId); if (Bytes.Length == 0) return ""; MD5 md5 = MD5.Create(); Byte[] HidBytes = md5.ComputeHash(Bytes); foreach (Byte b in HidBytes) HID += b.ToString("X2"); return HID; }
      
      







この方法では、ハードディスクのボリュームシリアルも追加されました。 仮想環境では、CpuIDとマザーボードのシリアル番号が検出されない場合があります(少なくとも0または例外が表示されます)。



WMIはハードウェア情報を取得するために使用されます。 対応する名前空間を接続することを忘れないでください:



 using System.Management;
      
      





WMIには、システムに関するほぼすべての情報を引き出すことができる膨大な数のクラスが含まれているため、必要に応じてリストを展開できます。



仕組み



ここで、作業のアルゴリズムを設定し、システムのライフサイクルに参加するデータを決定します。 データ交換の決定を複雑にしないために、HTTPプロトコルを使用します。 結局のところ、WEBはインターネット上で最も一般的なサービスであり、多くは現在、レンタルまたは独自のホスティングを持っているので、なぜその機能を拡張しませんか? したがって、我々は車輪を再発明するのではなく、ただ座って行きます。

私は面倒ではなく、図を描きました(UMLの専門家はご容赦ください)。 前述のように、クライアントとサーバーはHTTPを介して通信し、クライアントは必要なデータを収集し、POST要求でサーバーに送信します。



画像



サーバーは最終的にはPHPスクリプトであり、そのタスクはクライアントからデータを受信し、有効性を確認し、すべてが正常であれば、このデータをデータベースに保存し、最終的にクライアントに操作の結果を通知します。 サーバーの応答は次のように定義されます。





他のすべてのサーバー応答はエラーとして認識されます。 この例では、クライアントはアプリケーション内にあるソフトウェアモジュールであり、統計情報を収集します。 クライアントが送信するデータは次のとおりです。





これで十分でしたが、すべてが簡単に拡張可能です。

サーバーは、クライアントから送信されたデータに加えて、データの送信元のIPアドレスと日付も登録します。



お客様



すべてのクライアントコードをクラスにラップし、 AppCopyと呼びました 。 作業は非常に簡単です。シーケンス図を検討してください。



画像



ここで、APPは統計情報を収集するプログラムです。 まず、AppCopyクラスの代表が作成され、必要なすべてのパラメーターが渡されます。

次に、Registrationメソッドを呼び出す必要があり、クラスがその仕事を開始します。 完了すると、OnRegistrationCompliteイベントが発生し、そこで作業の結果が転送されます。 その後、クライアントが決定を行い、登録が成功した場合、それ以上の必要はありません。それが失敗した場合は、たとえばプログラムの次回起動時に再試行する必要があります。 それはすべて、実装と達成したい結果に依存します。



Appcopy
 class AppCopy { //   .  Sender -      , // ResultStatus -    public delegate void OnRegistrationRef (AppCopy Sender, RegResult ResultStatus); // .     public event OnRegistrationRef OnRegistrationComplete; //  public string MachineId; //   public string AppName; //   public string AppVersion; //   public string OsVersion; // URL   public string RegUrl; //     public int NumbersAttempts; //     () public int AttemtsInterval; //   public enum RegResult { //   Ok, //  ,     NetworkError, //    id   AlreadyExist, //    . NoAttempts }; //   Thread.       private Thread RegistrationThread; //   public RegResult ResultStatus { get; private set; } //   .    . public string HttpResponsetData { get; private set; } //  public AppCopy(string RegUrl, string MachineId, string AppName, string AppVersion, string OsVersion) { this.MachineId = MachineId; this.OsVersion = OsVersion; this.AppName = AppName; this.AppVersion = AppVersion; this.RegUrl = RegUrl; //===   === NumbersAttempts = 1; AttemtsInterval = 60000; ResultStatus = RegResult.NoAttempts; // ThreadMotion -  . RegistrationThread = new Thread(ThreadMotion); } //   public void Registration() { RegistrationThread.Start(); } //  .     private void ThreadMotion() { //  NumbersAttempts   for (int cntAttemps = 0; cntAttemps < NumbersAttempts; cntAttemps++) { SendRegistrationData(); //      if (ResultStatus == RegResult.Ok || ResultStatus == RegResult.AlreadyExist) break; // ,    AttemtsInterval . Thread.Sleep(AttemtsInterval); } //     OnRegistrationComplete.       OnRegistrationComplete(this, ResultStatus); } //      web .     private RegResult SendRegistrationData() { //  = string postString = "MachineID=" + this.MachineId + "&AppName=" + this.AppName + "&AppVersion=" + this.AppVersion + "&OsVersion=" + this.OsVersion; //     byte[] postBytes = Encoding.UTF8.GetBytes(postString); //     Stream dataStream = null; WebResponse response = null; StreamReader reader = null; try { //      HttpWebRequest request = (HttpWebRequest)WebRequest.Create(this.RegUrl); // ,     POST request.Method = "POST"; //   request.ContentType = "application/x-www-form-urlencoded"; //     request.ContentLength = postBytes.Length; //      dataStream = request.GetRequestStream(); // ""    dataStream.Write(postBytes, 0, postBytes.Length); // ,     response = request.GetResponse(); //       dataStream = response.GetResponseStream(); //     reader = new StreamReader(dataStream); this.HttpResponsetData = reader.ReadToEnd(); /*        .    ""  "EXIST_ID",       ResultStatus   .       . ""     HttpResponsetData */ switch (HttpResponsetData) { //    case "OK": ResultStatus = RegResult.Ok; break; //    case "COPY_EXIST": ResultStatus = RegResult.AlreadyExist; break; //     , APP_NOT_EXISTS,      (40*, 50*) default: ResultStatus = RegResult.NetworkError; break; } } catch { //   . ResultStatus = RegResult.NetworkError; } finally { //===  === if (dataStream != null) dataStream.Close(); if (reader != null) reader.Close(); if (response != null) response.Close(); } return ResultStatus; } }
      
      







少し説明します。 ネットワークでの作業は「長時間」と見なされます。接続が悪い場合(またはインターネットがまったくない場合)、アプリケーションは「フリーズ」し、ユーザーは赤い十字、または3つのボタンをクリックします。 したがって、Webサーバーで動作するコードを別のストリームに入れました。 これで、サーバーとの相互作用は顕著に発生せず、メインプログラムの動作に影響しません。 コードはよくコメントされているので、私はそれについて長々と言うつもりはありません。私はそれをどのように扱うかの例を示すだけです。



  static void Main(string[] args) { //    AppCopy appCopy = new AppCopy("http://test.info/reg_url.php", GetHID(), "Program_name", "Program_ver", GetOsVersion()); //    appCopy.OnRegistrationComplete += RegistrationFinish; appCopy.AttemtsInterval = 10; //  appCopy.Registration(); Console.Read(); } //   private static void RegistrationFinish(AppCopy Sender, AppCopy.RegResult ResultStatus) { Console.WriteLine("Registration result: {0} \nInformation: {1}", ResultStatus, Sender.HttpResponsetData); } private static string GetOsVersion() { ManagementObjectSearcher mos = new ManagementObjectSearcher("SELECT Caption FROM Win32_OperatingSystem"); string name = ""; foreach (ManagementObject mobj in mos.Get()) { try { name = mobj.GetPropertyValue("Caption").ToString(); } catch { }; } return name; }
      
      







GetOsVersion()関数はGetHID()と同様に機能します。バージョンではなく、「Windows 10 Enterprise ...」の形式でOS名を返します。 より簡単な方法で、.NET経由でOSバージョンを取得できます。



 Environment.OSVersion
      
      





しかし、このオプションは私にとってあまり有益ではないように思われました。



サーバー



そのため、プログラムは必要な情報をすべて収集し、サーバーに送信しました。 ここで、このデータを受け入れ、チェックし、成功した場合は適切な形式でデータベースに保存するタスクに直面します。 これはサーバーが行うことです。 さらに、サーバーは収集した情報を提供し、便利な形式でレポートを生成できる必要があります。



しかし、最初に、データベースを理解しましょう。 データベースは、 copysappssumの3つのテーブルで構成されています。



画像



コピーテーブルには6つのフィールドがあり、その意味は名前でわかります。 私はただ日付に注意し、IPはクライアントによって送信されず、サーバースクリプトによって受信され、 appidはプログラム識別子であり、外部(外部キー)キーであり、 appsテーブルへのリンクを形成します。 後者には3つのフィールドがあります:既知のappid 、ここでは主キー、 appnameおよびappverはそれぞれプログラムの名前とバージョンです。 システムは、この表にリストされているプログラム名とバージョンのみをカウントします。 そして最後に、 合計 -これは要約テーブルであり、結果の統計はここに保存されます。 テーブルにはappidsumの 2つのフィールドがあります。 登録の合計数が保存されるのは、 合計フィールドです。



トリガー(tg_new_copy)はコピーテーブルにバインドされ、新しいデータを追加(AFTER INSERT)した後に機能します(次のコピーを登録するとき)。 合計テーブルの合計フィールドの値を1つ増やします。 当然、 appidが登録されているプログラムのappnameappverに対応する場合にのみ、 合計の変更が発生します。



appsテーブルにはトリガー(tg_new_app)があり、これもデータを追加した後に機能します。 このトリガーのタスクは、 合計テーブルを初期化することです。



作業の論理は次のとおりです。 program1アプリケーション、バージョン1.0.0.0を作成しましょう。 システムにこのプログラムを通知して登録を開始するには、最初にappnameappverappsテーブルに追加します。 別の図を次に示します。



画像



新しいレコードが追加されると、appidが自動的に割り当てられ(上記の図-1)、トリガーtg_new_appが起動します 。これにより、先に取得したappidで新しいレコードsum = 0がsumテーブルに追加されます。



これで、プログラムに関するデータを収集する準備がすべて整いました。 コピーテーブルに新しい行を追加した後、 tg_new_copyトリガーは、同じ名前のテーブルの合計フィールドを1つ増やします



画像



十分な回路があると思うので、プログラミングを行います。 まず、データベースを準備する必要があります。テーブルとトリガーを作成し、関係を定義します。 これを行うために、システムの展開時に一度だけ実行する必要がある別のスクリプトを作成しました。 データベース接続パラメーター、テーブル名など 別のファイルに入れました それらはいくつかのスクリプトで必要になります。



config.php
 <?php //     //    $db_name = 'db_regapps'; //  $db_login = 'db_regapps'; //  $db_pass = '12345678'; //  $db_host = 'localhost'; //  $apps_table_name = 'tb_apps'; $stat_table_name = 'tb_copies'; $sum_table_name = 'tb_sum';
      
      







次に、データベース構成スクリプト:



setup.php
 <?php require 'config.php'; //    $db_handle = new mysqli($db_host, $db_login, $db_pass, $db_name); echo "   : <b> "; if ($db_handle->connect_errno) die(" </b> ($db_handle->connect_error)"); else echo " </b>"; // ===  === echo "<br>  $apps_table_name: <b>"; //     (app) $sql_query = "CREATE TABLE $apps_table_name (appid INT AUTO_INCREMENT NOT NULL PRIMARY KEY, appname VARCHAR(20) NOT NULL, appver VARCHAR(20) NOT NULL) CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE=InnoDB"; $result = $db_handle->query($sql_query); show_result(); echo "<br>  $stat_table_name: <b>"; //    $sql_query = "CREATE TABLE $stat_table_name (id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, machineid VARCHAR (32) NOT NULL, osver VARCHAR (128), appid INT NOT NULL, date DATETIME, ip VARCHAR(15), FOREIGN KEY fk_stat(appid) REFERENCES $apps_table_name(appid) ON UPDATE CASCADE ON DELETE CASCADE) CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE=InnoDB"; $db_handle->query($sql_query); show_result(); echo "<br>  $sum_table_name: <b>"; //   $sql_query = "CREATE TABLE $sum_table_name(appid INT NOT NULL , sum INT NOT NULL DEFAULT 0, FOREIGN KEY fk_sum(appid) REFERENCES $apps_table_name(appid) ON UPDATE CASCADE ON DELETE CASCADE) CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE=InnoDB"; $db_handle->query($sql_query); show_result(); // === === echo "<br>  tg_new_app: <b>"; $sql_query = "CREATE TRIGGER tg_new_app AFTER INSERT ON $apps_table_name FOR EACH ROW BEGIN INSERT INTO $sum_table_name SET appid=NEW.appid; END"; $db_handle->query($sql_query); show_result(); echo "<br>  tg_new_copy: <b>"; $sql_query = "CREATE TRIGGER tg_new_copy AFTER INSERT ON $stat_table_name FOR EACH ROW BEGIN UPDATE $sum_table_name SET sum= $sum_table_name.sum + 1 WHERE appid=NEW.appid; END"; $db_handle->query($sql_query); show_result(); $db_handle->close(); function show_result() { global $db_handle; if($db_handle->errno) die(" </b> ($db_handle->error)"); else echo " </b>"; }
      
      







メインコードをappstatクラスに最小化しました。



appstat.php
 class appstat { private $db_handle; //       private $last_error; //    private $apps_table_name; //   apps private $stat_table_name; //   copies private $sum_table_name; //   sum //  function __construct($db_name, $db_host, $db_login, $db_pass, $apps_table_name, $stat_table_name, $sum_table_name) { $this->apps_table_name = $apps_table_name; $this->stat_table_name = $stat_table_name; $this->sum_table_name = $sum_table_name; //     $this->db_handle = mysqli_connect($db_host, $db_login, $db_pass, $db_name); //   $this->last_error = mysqli_connect_error(); } //    .     ,    appid,  null public function add_app($app_name, $app_ver) { $app_id = $this->app_exist($app_name, $app_ver); if ($app_id != 0) return $app_id; //        ,   $sql_query = "INSERT INTO $this->apps_table_name(appname, appver) VALUES('$app_name', '$app_ver')"; mysqli_query($this->db_handle, $sql_query); $this->last_error = mysqli_error($this->db_handle); } //   .        public function delete_app($app_name, $app_ver) { // ,    ,    id $app_id = $this->app_exist($app_name, $app_ver); if ($app_id != 0) { $sql_query = "DELETE FROM $this->apps_table_name WHERE appid=$app_id"; mysqli_query($this->db_handle, $sql_query); } $this->last_error = mysqli_error($this->db_handle); } //      ,  0   . // ,  appid    private function app_exist($app_name, $app_ver) { $sql_query = "SELECT appid FROM $this->apps_table_name WHERE appname='$app_name' AND appver='$app_ver'"; $result = mysqli_query($this->db_handle, $sql_query); $this->last_error = mysqli_error($this->db_handle); if($result->num_rows === 0) { return 0; } else{ return $result->fetch_assoc()['appid']; } } //       . app_id -     //  0,    ,   id    private function copy_exist ($machine_id, $app_id) { $sql_query = "SELECT id FROM $this->stat_table_name WHERE appid='$app_id' AND machineid='$machine_id'"; $result = mysqli_query($this->db_handle, $sql_query); if ($result->num_rows != 0){ return $result->fetch_assoc()['id']; } return 0; } //    .  ,    , COPY_EXIST -    , //  APP_NOT_EXIXST -       . public function add_copy($machine_id, $os_ver, $app_name, $app_ver, $ip) { // ,       $app_id = $this->app_exist($app_name, $app_ver); if ($app_id != 0){ //  // ,        if ($this->copy_exist($machine_id, $app_id) === 0){ $sql_query = "INSERT INTO $this->stat_table_name(machineid, osver, appid, date, ip) VALUES('$machine_id', '$os_ver', $app_id, NOW(), '$ip')"; mysqli_query($this->db_handle, $sql_query); $this->last_error = $this->db_handle->error; return "OK"; } else{ //    return "COPY_EXIST"; } } else //    return "APP_NOT_EXIST"; } //   public function db_close() { mysqli_close($this->db_handle); } //         arr['appid', 'appname', 'appver', 'sum'] public function get_sum_apps_list() { $arr_result = array(); $sql_query = "SELECT $this->apps_table_name.appid, appname, appver, sum FROM $this->sum_table_name, $this->apps_table_name WHERE $this->sum_table_name.appid=$this->apps_table_name.appid"; $result = mysqli_query($this->db_handle, $sql_query); //    while ($row = $result->fetch_array(MYSQLI_ASSOC)) { $arr_result[] = $row; } $this->last_error = mysqli_error($this->db_handle); return $arr_result; } //         arr['machineid', 'osver', 'date', 'ip'] //          public function get_copys_list($app_name, $app_ver) { $appid = $this->app_exist($app_name, $app_ver); if ($appid != 0) { $sql_query = "SELECT machineid, osver, date, ip FROM $this->stat_table_name WHERE appid=$appid"; $result = mysqli_query($this->db_handle, $sql_query); $arr_result = array(); while ($row = $result->fetch_array(MYSQLI_ASSOC)) { $arr_result[] = $row; } return $arr_result; } } //    ,      arr['appname', 'appver', 'date', 'ip'] // machine_id - hardware ID  public function get_client_apps($machine_id) { $sql_query = "SELECT appname, appver, date, ip FROM $this->apps_table_name JOIN $this->stat_table_name ON $this->stat_table_name.appid=$this->apps_table_name.appid WHERE machineid='$machine_id'"; $result = mysqli_query($this->db_handle, $sql_query); $arr_result = array(); while ($row = $result->fetch_array(MYSQLI_ASSOC)) { $arr_result[] =$row; } return $arr_result; } //    . public function get_error() { return $this->last_error; } }
      
      







ここでは、コードにも十分なコメントが付けられているため、ここでは詳しく説明しません。



それを扱う方法



このすべての良い方法で作業する方法を示します。 まず、プログラムを登録する必要があります。これには、以下に示すフォームを使用できます。



appform.html
 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <titl>  </titl> </head> <body> <form action="http://test.info/regapp.php?Action=AddApp" method="post"> <label>AppName</label> <br> <input type="text" name="AppName" ><br> <br> <label>AppVersion</label><br> <input type="text" name="AppVersion" ><br> <br> <button type="submit" >Send</button> </form> </body> </html>
      
      





データはPOSTメソッドでregapp.phpスクリプトに送られ、そこにActionパラメーターが渡されます。これにより、スクリプトに必要な情報が通知されます。 パラメーターはGETメソッドによって渡されます。



regapp.php
 <?php require 'config.php'; require 'appstat.php'; //    $app_stat = new appstat($db_name, $db_host, $db_login, $db_pass, $apps_table_name, $stat_table_name, $sum_table_name ); if ($app_stat->get_error()) die("    ($app_stat->get_error())"); //      switch ($_GET['Action']) { //      case 'AddApp': //    if ((strlen($_POST['AppName']) == 0 || strlen($_POST['AppVersion']) == 0 )) { $app_stat->db_close(); die('   '); } else { $app_name = $_POST['AppName']; $app_ver = $_POST['AppVersion']; if ($app_stat->add_app($app_name, $app_ver) == false) echo " $app_name ($app_ver)  "; else echo '     '; } break; //   case 'AddCopy': //    if (strlen($_POST['MachineID']) == 0 || strlen($_POST['AppName']) == 0 || strlen($_POST['AppVersion']) == 0 || strlen($_POST['OsVersion']) == 0) { $app_stat->db_close(); die('   '); } else { $app_name = $_POST['AppName']; //   $machine_id = $_POST['MachineID']; // HardwarID $app_ver = $_POST['AppVersion']; //   $client_ip = $_SERVER['REMOTE_ADDR']; // Ip   $os_ver = $_POST['OsVersion']; //   //   echo $app_stat->add_copy($machine_id, $os_ver, $app_name, $app_ver, $client_ip); } break; } $app_stat->db_close();
      
      







ご覧のように、スクリプトは2つの操作を実行できます。これは、新しいプログラムをデータベースに追加し、次にAction = AddApp、2番目の操作はコピーの実際の登録です。この場合、ActionはAddCopyと等しくなります。



特に好奇心盛な人はフォームを使用して、手動でコピーを登録できます。



copyform.html
 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>  </title> </head> <body> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> </head> <body> <form action="http://test.info/regapp.php?Action=AddCopy" method="post"> <label>AppName</label> <br> <input type="text" name="AppName" ><br> <br> <label>AppVersion</label><br> <input type="text" name="AppVersion" ><br> <br> <label>MachineID</label><br> <input type="text" name="MachineID" ><br> <br> <label>OsVersion</label><br> <input type="text" name="OsVersion" ><br> <br> <button type="submit" >Send</button> </form> </body> </html> </body> </html>
      
      





画像



今すぐこれを行おうとすると、予期される応答APP_NOT_EXISTを受け取ります。したがって、最初にプログラムを登録します。



画像



今すぐ答えを取得します-OK



さらにもっと。appstatクラスには、テーブル形式のレポートを取得できる3つのメソッドがあります。その方法を示します。



showstat.php
 <?php require "config.php"; require "appstat.php"; $app_stat = new appstat($db_name, $db_host, $db_login, $db_pass, $apps_table_name, $stat_table_name, $sum_table_name); //   $result = $app_stat->get_sum_apps_list(); echo " <br>"; echo "<table border='1'><tr><th></th><th></th><th> </th></tr>"; for ($i = 0; $i < count($result); $i++) { $app = $result[$i]; echo "<tr><td>$app[appname] </td><td>$app[appver]</td><td>$app[sum]</td></tr>"; } echo "</table>"; echo "<br>"; //      echo "   <br>"; $result = $app_stat->get_copys_list('Program#1', '1.0.0.0'); echo "<table border='1'><tr><th>Machine ID</th><th> </th><th> </th><th>IP</th></tr>"; for ($i = 0; $i < count($result); $i++) { $copy = $result[$i]; echo "<tr><td>$copy[machineid]</td><td>$copy[osver]</td><td>$copy[date]</td><td>$copy[ip]</td></tr>"; } echo "</table>"; echo "<br>"; //    echo "  <br>"; $result = $app_stat->get_client_apps('666'); echo "<table border='1'><tr><th></th><th></th><th></th><th>IP</th></tr>"; for ($i = 0; $i < count($result); $i++) { $app = $result[$i]; echo "<tr><td>$app[appname]</td><td>$app[appver]</td><td>$app[date]</td><td>$app[ip]</td></tr>"; } echo "</table>";
      
      





この結果が



画像



得られました。デザイン、CSSなどは気にしませんでした。これに精通している人にやらせてください。タスクを設定するのは、データの取得方法を示し、作業を実証するためだけです。



そして最後に、すべてをライブクライアントでテストしましょう。記事の最初に戻り、appCopyオブジェクトの初期化パラメーターを次のように変更します。



 AppCopy appCopy = new AppCopy("http://test.info/regapp.php?Action=AddCopy", GetHID(), "Program#1", "1.0.0.0", GetOsVersion());
      
      





それだけです!プログラムを実行できます。応答として、結果を取得します



画像



。showstat.phpが生成するものを見てみましょう



画像



。表でわかるように、アプリケーションは正常に登録されました。クライアントを再度実行すると、そのようなコピーが既に存在するというメッセージがプログラムに表示されます



画像



。これですべてです。少し改良すれば、たとえば、ユーザーがプログラムでハングしている時間(特にゲームに関連する時間)に関する統計を収集したり、Javaでクライアントを書き換えたりして、Androidアプリケーションにコードを実装できます。



参照資料






All Articles