エス技研

WordPress、CakePHP、PHP、baserCMSなどの Web系システムを中心に情報を提供します!


乱数発生器(パスワード生成サービス)がバージョンアップで高速化!

   

乱数発生器(パスワード生成サービス)が Ver.2になって新登場!

 

乱数発生器(パスワード生成サービス) Ver.2

 
乱数発生器(パスワード生成サービス) Ver.2
https://s-giken.info/random/random.php
 
乱数発生器(パスワード生成サービス)ですが、内部処理を見直して、高速化したバージョン 2に生まれ変わりました。
 
乱数発生器(パスワード生成サービス)がバージョンアップで高速化!
 
これまでのツールは、30桁 10,000件でも「Fatal error: Maximum execution time of 30 seconds exceeded(最大 30秒の処理時間をオーバーしました)」というエラーが発生していました。
 
自分自身では、メールアドレスのパスワードを 10件程度生成する際などにしか使っていませんでしたので気づいていませんでしたが、数万件単位の乱数を生成しようとしたら、エラーで止まって使えない状態でした。
 
 
もともとこの乱数発生器を作ったのは、とあるキャンペーンで数十万件の乱数が必要になったからでした。
 
ペットボトルなんかにシールが付いていて、シールをはがして、それについている英数字を入力してキャンペーンにエントリーする、みたいなものの元になる乱数を生成する必要があったからでした。
 
当時のエクセルは 6万行ほどしかなくエクセルで生成することができなかったため、PHPでプログラムを生成して...というのがきっかけでした。
 
 
なので、そういう用途を見越して作成して、公開していたにもかかわらず、そういうキャンペーン用途では使えない状態だったことに気づいて、今回リニューアルをすることにしたのでした。
 
 

乱数発生器(パスワード生成)の高速化のポイント

 
今回の高速化にあたっては、2つの処理を見直しました。
 
1つ目が、乱数を発生させる関数を変更したことです。
2つ目が、重複チェックの処理方法を変更したことです。
 
 

乱数発生関数を変更して高速化する

 

 
かつての乱数を発生させる処理としては、「array_rand()関数」を使って、配列の中にある文字を取得する処理で文字を取得していました。
 
ですが、「array_rand()関数」では処理が遅いので、より高速な「mt_rand()関数」を利用することにしました。
 
 
「array_rand()関数」は内部で「rand()関数」を使用していますが、下記の PHPのマニュアルには「rand()関数」より「mt_rand()関数」の方が 4倍以上高速と書いてあります。
 http://php.net/manual/ja/function.mt-rand.php
 
 
実際の処理では、下記の様に、入力された桁数($ketasuu)の数だけ for文で繰り返し実行し、所定の桁数の文字列を生成しています。
 

 
さらには、この文字列を生成する処理を、求められる件数分実行する、ということですね。
 
 

重複チェックの処理方法を変更して高速化

 
乱数を生成する条件として、「重複を認める」というチェックボックスがあります。
これにチェックをを入れない場合は、生成した乱数の中に同じ乱数がないかどうかをチェックしながら乱数を生成する仕様になります。
 
これは、キャンペーンなどに使う乱数は、重複している乱数が入っているとトラブルの原因になりますので、重複を省く機能を実装していました。
 
 
ですが、この重複チェックをする機能が非常に重く、生成するレコードの件数が増えていくと、指数関数的に処理が重たくなる処理になっていました。
 
 
もともとの処理は以下のような感じです。
乱数を生成し、その生成した乱数が、生成した乱数の配列の中にあるかどうかを「in_array()関数」を使ってチェックし、重複していた場合は、カウントを戻してもう一度乱数を取得しなおす、という処理になっています。
 

 
ですが、乱数を一つ生成するごとに「in_array()関数」で重複チェックをしますので、件数が増えると徐々に重たくなっていくという一番ネックになっている処理でした。
 
 
そのため、あれこれ考えた結果、「array_unique()関数」を使って、全件生成した後に重複チェックをしよう、という決断を下しました。
 

 
 
これにより、劇的に高速化でき、40万件でも 10秒程度で生成できるようになりました。
 
実際の問題としても、桁数が多ければ多いほどほぼ重複はしませんので、最後に重複チェックをすれば OKという判断をしました。
 
 

重複チェックは最後でいいと判断した理由

 
乱数を生成した後に、「array_unique()関数」で重複チェックを実施すると、重複していた乱数は削除されるため、生成した件数がやや減ります。
 
具体的には、例えば、100件生成しても 2件の重複があれば 98件しか生成されません。
場合によっては、90件くらいしか生成されない場合もあるかもしれません。
 
それをどうしようかと考えたわけですが、100件必要な場合でも 100件ピッタリに生成する必要がある場合は皆無であろうと判断したわけです。
 
つまりは、100件必要なら、110件の生成で実行すればいい。
重複があって 105件くらいに減って出力されても、100件は超えているわけですので、あとはアナログ的に 5件削って 100件として使ってもらえばいいじゃないか、と。
 
処理が重くて必要な 100件が作れないより、問題はない、と判断したわけです。
 
 
それに、桁数が増えると、そもそもほぼ重複はしなくなるからです。
 
例えば、4桁の数字のみの場合。
生成される文字列は「0~9999」でありまして、10の 4乗の 1万通りあります。
 
この内、100件を乱数で生成した場合、重複する確率は 1万分の 100、1%になります。
つまりは、100件で生成すれば 99件くらいは生成されるわけです。
 
 
これが英数字を使った文字列の 4桁乱数の場合、
生成される文字列は、小文字 26文字、大文字 26文字、数字 10文字の合計 62文字の組み合わせになりますので、62の 4乗、14,776,336通りになります。
そして、この中から 100件を乱数で生成する場合、重複する確率は 14,776,336分の 100ですので、0.000677%となります。
これは、100件の生成を 1,000,000回実施すると 7回くらい 99件の場合があるかも、というくらいの確率です。
 
もしくは、4桁の乱数を 1,000,000件生成する場合には、7%くらい確率で 99件の場合があるかもしれない、という確率です。
 
なので、運が悪くなければ重複しない、と判断したわけです。
 
 
ちなみに、「乱数発生器(パスワード生成サービス) Ver.2」で生成できる最大の 30桁の乱数を生成する場合、生成できる文字列の組み合わせは、「5.9122213e+53」通りの乱数が生成できるわけです。
 
なので、桁数が増えれば増えるほど、重複しなくなるので、重複チェックは最後に確認程度に実施すればよろしかろう、という判断をいたしました。
 
 
それにより、劇的なスピード改善となり、数十万件のキャンペーン用の乱数コードを生成することも問題ない状態となりました。
 
 

乱数発生器(パスワード生成サービス) Ver.2 のまとめ

 
乱数発生器(パスワード生成サービス)ですが、最初に作ったのは 10年位前です。
その後、「エス技研ラボ」で提供する Webサービスとして作り直して、公開したわけですが、それから 4、5年経って高速化バージョンへのリニューアルとなりました。
 
 
前作は、「array_rand()関数」という便利な関数を知ったので、それを使いたい!と思って作ったこともありまして、スピードを気にせず構築していました。
 
ですが、件数が増えると全然使えないシステムだったことにようやく気付きまして、今回のリニューアルとなったわけですが、これで、本来の目的にも使ってもらえるんじゃないかと思っています。
 
ぜひとも、多くの方に使っていただければ、と思っています!
 
 
ちなみに、前作を公開したときの記事が下記にありまして、今回書いたところ以外の解説もありますので、あわせてごらんください。
PHP range関数を使って階乗と重複組み合わせを計算

 - PHP・Smarty・ECCUBE

GoogleAdwords

GoogleAdwords

最後までお読みいただきましてありがとうございます。
この記事が参考になったと思いましたらソーシャルメディアで共有していただけると嬉しいです!

Message

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

下記の空欄を埋めてください。 * Time limit is exhausted. Please reload CAPTCHA.

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)

※入力いただいたコメントは管理者の承認後に掲載されます。

  関連記事

ECCUBEの管理画面のSSL設定をインストール後に変更する方法

ECCUBEをインストールした後から管理画面のSSL設定を変更する方法を解説します。config.phpファイルのHTTPS_URLとADMIN_FORCE_SSLの値を変更すればOK。

PHPで特定の日間の日付を for、strtotimeで表示する

ある特定の間の日付の情報を for文、strtotimeを使って作成し、その解説をしています。

ECCUBE mtb_constants initパラメータ設定の項目を追加する方法

ECCUBEのパラメータ設定で設定できる項目を追加する方法を説明します。

ECCUBEでアップロードできない。upload_max_filesizeを設定する場所

テンプレートをアップロードする際に発生するエラー「テンプレートファイルがアップロードされていません」の対処方法。これはファイル容量の制限に引っかかっています。

PHPのソースで見慣れない記号が出てきた・アロー演算子(->)、ダブルアロー演算子(=>)

PHPのプログラムソースには見慣れない記号が出てきます。その意味や調べ方です。

JSON形式の値を配列形式に変換・PHPでは json_decode()、json_encode()
JSON形式の値を配列形式に変換・PHPでは json_decode()、json_encode()

JSONとは「JavaScript Object Notation」の略でテキストベースのデータフォーマット。JSONの値をPHPで配列に変換するWebツールの紹介とその処理「json_encode()」「json_decode()」関数の解説。

Smartyのテンプレート内の処理で計算、加工をする方法

Smartyのテンプレート上で変数を計算する、加工する方法を解説します。

GMOペイメントゲートウェイのjava.io.IOExceptionのエラー

ECCUBEの決済でGMOペイメントゲートウェイのモジュールを使ってテスト決済を行った場合の不具合、java.io.IOExceptionと言うエラーの原因と対策方法の解説です。

AdminerはphpMyAdmin代替のデータベース管理ツール

AdminerはphpMyAdminとほぼ同機能のデータベース管理ツール。PHP 1ファイルのため設置が非常に簡単で軽快に動作し、phpMyAdminの置き換えで使うのも問題なし。

連想配列のキーも値もまとめてhtmlspecialchars()でサニタイズする関数の作成解説
連想配列のキーも値もまとめてhtmlspecialchars()でサニタイズする関数の作成解説

PHPの配列・連想配列のキーと値をまとめてhtmlspecialchars()関数でサニタイズ(無害化、無毒化)を行う関数を作成。連想配列のキーはarray_map()関数でのサニタイズは無理。