エス技研

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


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

      2018/01/07

乱数発生器(パスワード生成サービス)が 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関数を使って階乗と重複組み合わせを計算
 
 
また、JavaScriptを利用して、入力エリアの横に「パスワードを生成する」ボタンを追加する機能について下記に記事を書いています。あわせてご覧ください。
JavaScriptで「パスワードの生成」ボタンを追加する処理サンプル

 - PHP・Smarty・ECCUBE

GoogleAdwords

GoogleAdwords

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

Message

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

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

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

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

  関連記事

PHPのcURLでAPIやWebサイトへのアクセス方法。file_get_contentsとの比較
PHPのcURLでAPIやWebサイトへのアクセス方法。file_get_contentsとの比較

PHPからWebサイトにアクセスしてHTMLを取得、APIにアクセスして情報を取得する場合は、cURLがオススメ。file_get_contentsでも可能だがエラー制御に難がありトラブルのもとになる。

PHPで正規表現の検証には preg_match_allが便利

PHPで正規表現の検証には preg_match_allが便利です。その便利さの使い方の解説です。

PHPのスクレイピングライブラリ「PHP Simple HTML DOM Parser」の使い方
PHPのスクレイピングライブラリ「PHP Simple HTML DOM Parser」の使い方

PHPのスクレイピングライブラリ「PHP Simple HTML DOM Parser」の使い方を解説。要素を取得する方法、そこから属性を取得する方法を解説。また、マニュアルにはない注意点なども解説。

SEO対策用タイトル、ディスクリプションの文字数カウントツール

SEO対策に使える文字数カウントツールで文字数の条件の説明も行っています。

Phpmailerでスパム回避!Gmail等のSMTPを経由するPHPのメールフォーム解説

お問い合わせ等のメールフォームから送ったメールがスパム扱いされる!その対策としてライブラリ「Phpmailer」を使う方法を解説。関数化していますのでコピペでOK。

サーバ移転、PHPバージョンアップでPHPのソースコードが表示される・ショートタグのPHPが動かない

PHPでショートタグを使うのは危険。サーバ移転やバージョンアップで動かなくなる!ソースが丸見え、設定情報流出のリスクが!php.iniのshort_open_tagの設定を再確認。

include、requireのパス指定をdirname(__FILE__)、__DIR__と書く理由

include、requireのパスの指定を dirname(__FILE__)、__DIR__で記述する理由に付いて解説。相対パス、絶対パスを直書き、パスを書かない場合は何が問題かを説明。

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

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

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

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

ECCUBEを開発環境から本番ドメインに変更でエラーが・パス変更について

レンタルサーバでサーバ会社から割り当てられたURLで開発し、本番公開時にドメインを当てたらエラーが!そんな場合の対処方法の解説。対処方法は簡単ですが管理画面からは対応不可。