• ベストアンサー

請求書等のシリアル番号生成方法?

請求書(E-mai本文用)等に使用するシリアル番号の生成の仕方を知りたいのですが、どうすればよいのでしょうか? 「マクロ秒とかを使用するのかな?」とも思いますが。 できれば、きっかけとなる関数や知識などをお教え下さい。 簡単なコードなどでも結構です。 シリアル番号を連番で出す場合とランダム出す場合では、方法が違うように思いますが。一様、両方の方法を試してみたいです。 よろしくお願いします。

  • PHP
  • 回答数6
  • ありがとう数25

質問者が選んだベストアンサー

  • ベストアンサー
  • galluda
  • ベストアンサー率35% (440/1242)
回答No.5

がるです。 んと…大して高度な事をやっているわけでもないのですが(苦笑 文字列が長くなってもよいのであれば、例えば、こんなコードがありえます。 function tokenizer() { // 秒&マイクロ秒を取得 list($usec, $sec) = explode(" ", microtime()); // ここはデフォルト // エポック秒:まぁ全部はいらんのでちょっと小さめに $tokens[] = $sec - 1079340000; // マイクロ秒 $tokens[] = (int)($usec * 1000 * 1000); // プロセスID $tokens[] = getmypid(); // 乱数 $tokens[] = mt_rand(); // return implode('-', $tokens); } 参考にでもなれば幸いです。

kitty1000
質問者

補足

galludaさん ご回答、ありがとうございました。 >大して高度な事をやっているわけでもないのですが 高度でなくて結構です。高度だとこちらが理解できません。 >文字列が長くなってもよいのであれば、例えば、こんなコードがあり >えます。 了解しました。ただし、こちらの必要な文字列は数字6桁です。 上記のgalludaさんのコードを改良しようとも思いましたが、番号の衝突する確率を上げずに出力する乱数の桁数を6桁にするためには、どこをいじればよいのか分かりません。どこをいじれば、番号の衝突する確率を上げずに出力する乱数の桁数を数字6桁に整えられるのでしょうか? やはり、6桁にするには他のコードが必要ですかね? よろしくお願いします。

その他の回答 (5)

  • sak39
  • ベストアンサー率0% (0/1)
回答No.6

6桁の数字と言う制限がどこからやってくる物なのか分かりませんが、エポック秒+マイクロ秒を5年間の間を概算すると5*365.25*24*60*60*1,000,000≒1.5×10の14乗となり、10進数で15桁(例えばミリ秒単位まで切下げても それでも12桁)くらい必要になってしまいます。これは、5年間でまた似たような値にサイクリックして来る(5年で一周してまた元の値に戻って来る)場合まで値を切り捨てた場合で、時間的には最小限度の必要な値に桁数を抑制したケースでの桁数です。(具体的には、エポック秒を5年間相当の秒数で割った時の余りを値として使用する) 仮に6桁の数字(10進数)と言う制限を 数字だけからアルファベットA~Zの26文字も含んで良い事としても、6桁の制限でアルファベット数字交じりとしても、36の6乗=2,176,782,336 (10桁)となり、15桁の値には遠く及びません。(つまり エポック秒+マイクロ秒をアルファベット数字交じり6桁に変換しようと思っても、桁数が少なすぎて1対1変換ができない) 時間的桁数だけで15桁(もしくは12桁)も要する手法なため、これは不可能と言う事になります。 (これは前の回答にも示した内容では有りますが…、)ご質問にある乱数の手法でも一回一回の値の振り出し時に常に一定の直前との値の重複(衝突)の確立を持ち、且つ 長期に渡って使用し続ければその衝突の確立は結果的に無視できない大きさになって来ると思われます。 時間的要素として、エポック秒+マイクロ秒に加え、衝突を防ぐ為の組み合わせを行う他の数字(つまり接続されコールされる事で発生するプロセスIDとか 接続元IPアドレスの様なもの)も、たまたま時間的に同時に重なって別端末(PC)からコールされた物でも違う物として判別できるようにする工夫として使えるのですが、更に桁数を必要とする事になります。 また、ご質問のケースの必要性から単純に同時接続している端末の端末接続順番の番号の様な単純で小さい値が実際 欲しいだけなのですが、この端末のIDの様な値は、端末の固有IDの様なもので、値の桁数は必要以上に大きい物です。 回答側で出している時間的な違いを利用して一意の請求番号を振り出す手法(エポック秒などを使う手法)は、簡単にIDを振り出す効果的な手法では有ります。 しかし、残念ながら、振り出し番号の衝突をDBで確認して別番号を振らないのであれば、衝突の危険性が全くない様にして、5年間の長期に渡って6桁に圧縮する術は無いと思われます。

kitty1000
質問者

補足

sak39さん ご回答、ありがとうございました。 了解しました。

  • sak39
  • ベストアンサー率0% (0/1)
回答No.4

ANo.3 galludaさんの回答が、妥当だと思います。 乱数での解法が妥当かどうかのご質問が有ったので意見を述べさせていただきます。 PHPのプログラマでないので、合っているか分かりませんのでご参考までですが、 mt_srand((double)microtime()*1000000); とやるとmicrotime()が返すスペース文字以降の秒数部分を無視し、マイクロタイムのみを演算対象として乱数の初期化をする事になると思います。 mt_randの取得乱数列でぶつからないとしても、同じマイクロ秒になって乱数の初期化自体が同じになってしまう5年間の間の確立は、m枚/月の請求書発行時で、平均0.00006×m回程度(5年*12ヶ月*月m回/1,000,000)となり、運が悪ければ衝突が発生する事になります。 確実に重ならないようにしたいのであれば、もう少し複雑な方法が必要だと思われます。 マイクロ秒単体では、重ならない保障は出来ません。また、日時だけでも、もちろん駄目ですし、接続により発生するIDの様な物についても同様にそれ単体では、同じIDがまた何時発生するか分かりません。それらを組み合わせた時点で初めて一意の値を作り出せます。 「いや、衝突すればエラーになるよ。 再度やり直せばOK。 また衝突発生率は、非常に低い。」等と言う事で十分であれば、その発生頻度の許容範囲を考える必要性があると思います。 請求書発行済み番号がDBに登録されているなら、それを検索して発行済みで有るかどうか確認でき、振り出し請求書番号の衝突時に 再度乱数を取得するのであれば、おっしゃる乱数を単純に使う方法も利用できると思いますが、ご質問の意図を察するに、これは違うとは思います。 また、そもそもDBを使えるなら、排他ロックして番号をシーケンシャルに振る事も容易なのですが…。

kitty1000
質問者

補足

sak39さん ご回答、ありがとうございました。 了解しました。 >確実に重ならないようにしたいのであれば、もう少し複雑な方法が必 >要だと思われます。 galludaさんのご説明はなんとなく分かるのですが、わたしには難しすぎてコーディングができません。 galludaさんのご説明されている方法ほど完璧でなくとも、私のコードよりは格段に衝突の起こりにくいコーディングを教えていただけるでしょうか(私のを改良する形でも結構です。)? galludaさんへの補足にも書きましたが、今回はデータベースは使用しません。フォームの入力内容に基づきPHPで生成した請求書メール(請求書番号付き)を、フォーム入力者へ送信するのみです。 よろしくお願いします。

  • galluda
  • ベストアンサー率35% (440/1242)
回答No.3

がると申します。 連番の場合、適切にファイルロックなりトランザクションなりを組み合わせていただくとして。 単純に「ユニークな文字列」を作成する場合、私が使ってるロジックは ・エポック秒 ・ミリ秒またはマイクロ秒 ・プロセスID ・(スレッドID ・(localなIPアドレス ・(乱数 をつなげた文字列を使っています(厳密には、上述の数字を、62進数という文字列に変換して使用)。括弧は「必要に応じて」という感じです。 とりあえずこのやり方で、特殊な状態を除いて「確実にユニークな文字列」が取得できます。 なお、ハッシュ関数(MD5など)は、厳密には「コリジョン(衝突)」の可能性があるので、私は勧めません。…まぁ「滅多にない」のですが。 以上私見ですが参考になれば幸いです。

kitty1000
質問者

お礼

galludaさんのご説明はなんとなく分かるのですが、わたしには難しすぎてコーディングができません。 galludaさんのご説明されている方法ほど完璧でなくとも、私のコードよりは格段に衝突の起こりにくいコーディングを教えていただけるでしょうか(私のを改良する形でも結構です。)? 上記補足にも書きましたが、今回はデータベースは使用しません。フォームの入力内容に基づきPHPで生成した請求書メール(請求書番号付き)を、フォーム入力者へ送信するのみです。 よろしくお願いします。

kitty1000
質問者

補足

galludaさん ご回答、ありがとうございました。 理論的にはなんとなく分かるのですが、どのようにコーディングするのか不明です。また、今回はデータベースは使用しません。

  • sak39
  • ベストアンサー率0% (0/1)
回答No.2

書類は5年保存などが基本なので、その範囲で重ならない事を考えると、西暦年の下1桁、月(2桁)、日(2桁)、時(24時制 2桁)、分(2桁)、秒(2桁)、ミリ秒(3桁)を算術演算で組み合わせる方法が考えられると思います。そのまま全部組み合わせれば、14桁になりますが、桁数を抑えるのであれば、(((((年(1桁)×12+月(2桁)-1)×31+日(2桁)-1)×24+時(24時制 2桁))×60+分(2桁))×60+秒(2桁))×1000+ミリ秒(3桁)などで、計算するのも良いかと思います。 今回のご質問では関係ないかもしれませんが、人間の手で番号を割り振る場合は、年月日に001(一日発生する請求件数を下回らない桁数)などその日の連番を加えて割り振る場合が有りますが、請求番号だけで日付が分かり、検索しやすいなどのメリットが有ります。 Windows APIを使えるなら、GetLocalTime関数でSYSTEMTIME構造体に現在日時をゲットしてミリセカンドを取得すれば最後のミリ秒3桁に使えると思います。 ミリ秒でも重なりの可能性が有るなら、乱数を更に計算桁に加える方法も有ると思います。

kitty1000
質問者

お礼

下記の乱数で重なりの可能性は、あるのでしょうか? mt_srand((double)microtime()*1000000); $example = mt_rand(100000, 999999); ある場合は、連番でもランダムでも結構ですから、数字が重ならないようにするには、どうすればよいでしょう。 できるだけ単純な方法をお願いします。

kitty1000
質問者

補足

sak39さん ご回答、ありがとうございました。 下記のような単純なものを考えていたのですが、問題ありますか? mt_srand((double)microtime()*1000000); $example = mt_rand(100000, 999999); 数字が6桁で出てきます。 よろしくお願いします。

  • yambejp
  • ベストアンサー率51% (3827/7415)
回答No.1

適当なキーワード+連番でidつくり、MD5などでハッシュするとか いろいろあるでしょうけど、履歴性などをかんがえるなら あらかじめRDBに連番とシリアル対比表になるデータをつくっておいて 必要に応じて払い出してもらうのが妥当かと。

kitty1000
質問者

補足

yambejpさん ご回答、ありがとうございました。 今回はデータベースを使用しない単純な方法を模索しています。 連番でなくて、ランダムな値で結構ですが、一つ一つの番号が違うようにしたいです。 よろしくお願いします。

関連するQ&A

  • 10000通りのシリアル番号を生成したい

    10000通りのユニークなシリアル番号を生成させるプログラムを 作りたいと考えています。 00000 00001 00002 ... 99998 99999 という数字が縦に並んだテキストファイルを用意して、それを読み込んで 00000→8401923 00001→4234420 00002→1354234 ... 99998→4235662 99999→9557346 というような7桁の数字だけのシリアル番号を作りたいのです。 また、一つのシリアル番号、仮に8401923という数字を利用して 下一桁をちょっと変更したぐらいでは、 他のシリアル番号にHitしないような作りにしたいと思います。 10000までの連番の数字に、何かしらのマスク処理をかけて シリアル番号を生成させる感じだと思うのですが その、マスクの部分の具体的な処理がよくわからないのです。 また、シリアル番号から、元の連番の数値も出したいと考えていますが それもどのように処理させればいいのでしょうか? 以上になりますが、どうぞよろしくお願い致します。

    • ベストアンサー
    • Perl
  • 連続したシリアルを自動生成する方法

    連続したシリアルを自動生成する方法 VBA入門したばかりの初心者です。 業務で使用するのですが、お力を貸していただければ助かります。   A     B 1 コード   1111 2 数量     40 3 シリアル  25250 毎回するのはB1:B3です。 シリアルは先頭のシリアル番号であり、数量分連番で作成しなければなりません。 最終的にはコードをタイトルとしたテキストファイルに 数量分のシリアルを出力したいのです。 ですが、初歩的な部分でシリアルの生成ができません。 一度"SHEET2"などにシリアルを生成するか、"SHEET1"の空きスペースに作成しても 構いません。(まだ構造がはっきりできていないのでモヤモヤしています) 使用環境: winXP SP2 Excel2000(9.0) 不足情報があればご指摘くださいますよう、お願いいたします。

  • 完全な乱数を生成する方法

    C言語で乱数を生成するときに、今まで srand(time(NULL)); を使用していたのですが、それだと1秒以内に複数の処理を行った際に、 同一の乱数が生成されてしまいます。 時間にとらわれずに完全にランダムな数字を出現させるにはどのような方法を取るのが簡単なのでしょうか? よろしくお願いします。

  • Word2010 連番生成順をコントロールしたい

    お世話になります、 Word2010です。 エクセルなどの外部ファイルを用いず、 出来ればWordのみで 出現順のコントロールを含めて 連番の自動生成をさせたく思っています。 今日試しにしてみた所、 番号の生成は出来たのですが、 出現順がテンでバラバラで 重複こそないものの 連番としては はなしにならないものでした。 お教えください、 フィールドコードによる連番生成に際し、 その出現順を整える方法は ありますでしょうか? どうぞ湯路しくお願いします。

  • 乱数の生成方法

    乱数を生成するソースコードを探しています rand関数で生成される乱数はよい乱数ではないようで それ以外でいい乱数を生成する方法はどのようなものがあるのでしょうか また、実装したソースコードのサンプルがあればWEBページなどを教えていただきたいです

  • シリアル番号はどこ

    筆まめver30を自動アップグレードにて使用していますが以前バージョンver28~29をアンインストールしたらシリアル番号の入力を要求され使用できなくて困っています。 自動アップグレードした場合製品のシリアル番号はどこで確認できますか? ※OKWAVEより補足:「ソースネクスト株式会社の製品・サービス」についての質問です。

  • PHPで15桁程度のユニークコード生成

    md5() や sha1() などでランダムなコードは生成できますが、15桁程度でユニークなコードを 生成するとなった場合、どの様なものがあるでしょうか? 生成する度に以前生成したものに存在するか確認しなくても良い方法がありましたら 教えていただきたいです。

    • ベストアンサー
    • PHP
  • シリアル番号検索を早くする方法

    office2016 (1)ORACLEからシリアル番号とその工事名称をexcelへインポート (2)シリアル番号に対する工事名称を確認して、作業工程のデータを作成 (3)作成した作業工程のデータをORACLEへ登録 というデータ作成をしています。 もともとは、(1)、(2)は無しで対応していたのですが、シリアル番号を手入力すると間違えるので、(1)、(2)の内容を追加しました。 登録されているシリアルの数が多い(4万件ほど)ので、先頭1桁目の文字列、先頭2桁目の文字列抽出、先頭3桁目の文字列抽出、先頭4桁目の文字列抽出をし、 あとは、先頭4桁で絞ったシリアル番号の集まりにして、その中からプルダウンメニューで対象のシリアル番号を特定させるという構成にしています。 シリアル番号の桁数は8桁。先頭4桁は英数文字、後半4桁はほぼ数字。若干英文字混じる。 MENUシート 工事番号の絞り込みとその工事番号の名称表示を実施 A13セル:シリアル番号1桁目を表示。入力規則 =SERIAL!$H:$H B13セル:シリアル番号2桁目を表示。入力規則 =SERIAL!$iI$I C13セル:シリアル番号3桁目を表示。入力規則 =SERIAL!$J:$J D13セル:シリアル番号4桁目を表示。入力規則 =SERIAL!$K:$K E13セル:8桁のシリアル番号表示。入力規則 =KOJI!$A:$A SERIALシート ORACLからインポートしたデータ表示 A列:シリアル番号 B列:工事名称 C列:シリアル番号の1桁目表示 D列:シリアル番号の2桁目表示 E列:シリアル番号の3桁目表示 F列:シリアル番号の4桁目表示 G2セル:MENUシートで先頭4桁の番号表示 =MENU!A13&MENU!B13&MENU!C13&MENU!D13 H列:インポートしたシリアル番号の先頭1桁目に使用されている文字列表示 I列:インポートしたシリアル番号の先頭2桁目に使用されている文字列表示 J列:インポートしたシリアル番号の先頭3桁目に使用されている文字列表示 K列:インポートしたシリアル番号の先頭4桁目に使用されている文字列表示 KOJIシート 先頭4桁で絞り込んだシリアル番号の集まりを表示する マクロ MENUシート Private Sub Worksheet_Change(ByVal Target As Range) If (Target.Column = 1 Or Target.Column = 2 Or Target.Column = 3 Or Target.Column = 4) And Target.Row = 13 Then chushutsu Else End If 標準モジュール Sub chushutsu() Application.ScreenUpdating = False Sheets("KOJI").Select Columns("A:B").Select Selection.ClearContents Sheets("SERIAL").Select Range("G1") = "SERIAL" Range("G2") = "=MENU!R[11]C[-6]&MENU!R[11]C[-5]&MENU!R[11]C[-4]&MENU!R[11]C[-3]" ' Columns("A:B").AdvancedFilter Action:=xlFilterInPlace, CriteriaRange:= _ Range("G1:G2"), Unique:=False ' Cells.Select Selection.SpecialCells(xlCellTypeVisible).Select Selection.Copy Sheets("KOJI").Select Range("A1").Select ActiveSheet.Paste ActiveWorkbook.Worksheets("KOJI").Sort.SortFields.Clear ActiveWorkbook.Worksheets("KOJI").Sort.SortFields.Add Key:=Range("A:A"), _ SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal With ActiveWorkbook.Worksheets("KOJI").Sort .SetRange Range("A:B") .Header = xlYes .MatchCase = False .Orientation = xlTopToBottom .SortMethod = xlPinYin .Apply End With Sheets("SERIAL").Select ActiveSheet.ShowAllData Sheets("MENU").Select Application.ScreenUpdating = True End Sub 問題なのは、MENUシートのA13,B13,C13,D13セルでプルダウンメニューから文字を選択する度にマクロが動作するのに、若干時間がかかること。 シリアル番号を検索するのに、基本、先頭1桁目から順番に絞り込みます。 なので計算方法を手動にしておき、先頭1桁目から3桁目まではマクロ動作させず、4桁目を指定した後にマクロ実行するという手もありますが、後から2桁目の文字だけ変更して別のシリアル番号検索という場合もあるので対応できません。 CTRL+Fで工事番号を手入力して検索したらすぐに探せますが、手入力は面倒なので、先頭4桁の文字をプルダウンで特定して絞り込むという構成のままで検索時間の短縮が図れる構成としたいです。 マクロに関してはベタで教えていただきたく。

  • SD-JukeboxV5のシリアル番号が解らない!

    au携帯についていたSD-JukeboxV5を使用してますが、パソコンにインストール後にCDのケースを無くしてシリアル番号が判りません。このままだとパソコンがクラッシュした場合、再インストールが出来ませんのでシリアル番号を調べる方法があればお教えいただけないでしょうか! よろしくお願いします。

  • シリアル番号の変更について

    インストール済みのウィルスセキュリティーのシリアル番号の変更は可能ですか。可能の場合、方法を教えてください。