エス技研

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.

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

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

  関連記事

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

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

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

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

PHP range関数を使って階乗と重複組み合わせを計算

PHPの range関数を使って階乗と重複組み合わせを計算し、それを元に乱数発生器を作成しました。

ECCUBEの問い合わせフォームに任意の値を引数として渡す方法

ECCUBEのお問い合わせフォームに値を固有の情報を送りそれに基づいて処理をする方法を解説。ボタンの設置、受け取り側のテンプレート、プログラムのサンプルソースを提供。

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

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

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

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

Basic認証の.htaccess、.htpasswd生成ツールと解説

Basic認証を設定する際に必要となる.htaccess、.htpasswdファイルを生成するツール。ID、PASS、.htpasswdへのパスを入力することで編集する情報を生成します。

Smartyの修飾子regex_replaceで正規表現の後方参照・PHPではpreg_replace

ECCUBEで使われているSmartyで文字列を正規表現で置換し後方参照で値を利用する装飾子regex_replaceの解説です。細かな条件がありますので注意が必要です。

路線・駅検索をPHPで実装する方法解説。GoogleMapsの緯度経度から計算し検索
路線・駅検索をPHPで実装する方法解説。GoogleMapsの緯度経度から計算し検索

路線・駅検索の仕組みの構築は大変。登録する側も最寄り駅が多い場合は大変。なので簡易に実装するため緯度経度に基づき直線距離を計算する処理を考案して実装して、その処理を解説。

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

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