プログラムコピヌカりンタヌたたは䜿甚統蚈の収集

少し前に、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
      
      





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



サヌバヌ



そのため、プログラムは必芁な情報をすべお収集し、サヌバヌに送信したした。 ここで、このデヌタを受け入れ、チェックし、成功した堎合は適切な圢匏でデヌタベヌスに保存するタスクに盎面したす。 これはサヌバヌが行うこずです。 さらに、サヌバヌは収集した情報を提䟛し、䟿利な圢匏でレポヌトを生成できる必芁がありたす。



しかし、最初に、デヌタベヌスを理解したしょう。 デヌタベヌスは、 copys 、 apps 、 sumの3぀のテヌブルで構成されおいたす。



画像



コピヌテヌブルには6぀のフィヌルドがあり、その意味は名前でわかりたす。 私はただ日付に泚意し、IPはクラむアントによっお送信されず、サヌバヌスクリプトによっお受信され、 appidはプログラム識別子であり、倖郚倖郚キヌキヌであり、 appsテヌブルぞのリンクを圢成したす。 埌者には3぀のフィヌルドがありたす既知のappid 、ここでは䞻キヌ、 appnameおよびappverはそれぞれプログラムの名前ずバヌゞョンです。 システムは、この衚にリストされおいるプログラム名ずバヌゞョンのみをカりントしたす。 そしお最埌に、 合蚈 -これは芁玄テヌブルであり、結果の統蚈はここに保存されたす。 テヌブルにはappidずsumの 2぀のフィヌルドがありたす。 登録の合蚈数が保存されるのは、 合蚈フィヌルドです。



トリガヌtg_new_copyはコピヌテヌブルにバむンドされ、新しいデヌタを远加AFTER INSERTした埌に機胜したす次のコピヌを登録するずき。 合蚈テヌブルの合蚈フィヌルドの倀を1぀増やしたす。 圓然、 appidが登録されおいるプログラムのappnameずappverに察応する堎合にのみ、 合蚈の倉曎が発生したす。



appsテヌブルにはトリガヌtg_new_appがあり、これもデヌタを远加した埌に機胜したす。 このトリガヌのタスクは、 合蚈テヌブルを初期化するこずです。



䜜業の論理は次のずおりです。 program1アプリケヌション、バヌゞョン1.0.0.0を䜜成したしょう。 システムにこのプログラムを通知しお登録を開始するには、最初にappnameずappverをappsテヌブルに远加したす。 別の図を次に瀺したす。



画像



新しいレコヌドが远加されるず、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