- ベストアンサー
クッキーセット直後、クッキーを参照することは無意味?
- クッキーセット直後に同一プロセスからクッキーを参照することは無意味です。クッキーはブラウザ側に送られても、環境変数はサーバ側にあり、自動更新されません。
- セットしたクッキーを参照するためには、そのプロセス終了後に新たなプロセスで参照する必要があります。クッキーを食わせるプログラムと、クッキーを参照するプログラムは分けて起動する必要があります。
- クッキーを参照したい場合は、クライアントからサーバ側のプロセス開始オーダーがあったときに必要なデータをクライアント側が送信し、サーバはそのデータから環境変数群を構成してプログラムを開始する必要があります。
- みんなの回答 (4)
- 専門家の回答
質問者が選んだベストアンサー
> <<あくまでも「クライアントの指示」でサーバ側のプロセス開始オーダーがあったときのみ必要なデータをクライアント側が送信し、サーバはそこからプロセスに必要なデータから環境変数群を構成してプログラムを開始するのです。 > ここら辺をもう少し分かりやすく解説していただけませんか? > もしくは分かりやすく書かれたサイトを教えていただけませんか? まず、Webサーバ側(以下サーバ側)とWebページを見たい側(以下クライアント側)に分けて考えましょう。 普段はサーバ側は待ちの状態にあります。 クライアント側からページを見せろと要求があれば、その要求が真っ当なら、サーバ側はそのデータをクライアント側に返信します。 Webサーバというのは要求のあったデータを返信するだけの単純な仕組みに過ぎません。 次に、クライアント側が要求とともに送信するデータに応じて、サーバ側で返信内容を加工して動的なデータをクライアント側に返信するようなケースでは サーバ側では返信の前にクライアント側から送信されてきた内容を解釈して、それを元に処理を行い結果を返信する このとき、WebサーバはOSの標準入出力(cでいうところのstdio)を通して指定プログラムの実行を要求します(Webサーバが直接実行するわけではないことに注意してください。動作するプログラムはOS環境下でWebサーバというユーザ権限で実行されるのです)。 この仕組みをCGIといいます。 このようにWebサーバはクライアントからの要求を単純に処理して返信するだけ(タレ流し)の仕組みで、基本的にサーバ側からクライアント側に対してなにかを行うものではありません。 タレ流されてくる先頭部分には、後にタレ流すデータの種類(HTML/画像/ベタテキスト/音楽・・・etc)とか、サイズ、ブラウザへの指示(キャッシュを利用するしないとか)、そしてcookie情報なんかがまとめてあって改行連続2回のその後に、HTMLデータやなんかが送られてくる。 ここで送られてくるcookieに注目すると、ブラウザは受け取ってcookieエリアに保存するだけでおしまい。 サーバ側に対してその情報からアクションを起こすわけではないのです。 今度は少し戻って、サーバ側からの視点で見ると、クライアント側からCGIの要求があれば、要求とともに送られてくる各種情報、返信用IPアドレス(どこに返信するかわからないと困りますよね)、返信用ポート番号(同じマシンでブラウザ2個表示して同時に同じサイトに要求してもデータがごっちゃにならないように)、cookie情報(当然ドメインやパスが一致して期限切れでないもの)、フォームやURLのメソッドデータなどなどさまざまな情報を受信し終わった後に、処理を開始します。 受信した情報はその呼ばれたCGI専用のプロセスに環境変数や標準入力バッファを構築してシステムに実行オーダーを出します。 実行時の標準出力データを出力バッファに蓄えてクライアント側にヘッダ情報とともに垂れ流し終了です。 呼び出されるプログラムは、クライアント側のcookieを直接参照するわけではなく、クライアント側から初期呼び出し時に能動的に送られてきた情報を元に構築された環境変数を介して参照するのです。 サーバ側からのデータで書き込まれたcookieはサーバ側から直後に読み出すことは不可能なのです。なぜなら環境変数は処理前の初期状態をキープしているからです。 また、クライアント側でcookieが正常に書き込まれたかどうかなんていちいち知ったこっちゃないのです。それはクライアント側の問題であってサーバ側の問題ではないからです。 cookie情報はクライアント側にあって、サーバ側にあるわけじゃないのです。 たとえ話は誤解を生む可能性がありますがあえていうと この通信は電話ではなく手紙だと思ってください。 1.このプログラムを実行して結果をくれと手紙を出す 2.これが結果だと返信がくる。その中にはcookie情報があるので憶えておけと書いてある 3.クッキーを見せるプログラムを実行して結果をくれと2度目の手紙を出す(じつはその手紙にはいろんなものと一緒にcookie情報が書いてある) 4.その手紙からcookieを判別して、これがお前のcookieだと返信がくる。 > <<セットしたクッキーを参照したいなら、そのプロセス終了後に新たなプロセス(プログラムを別にする)で参照するしかないでしょう。 > > 要するにクッキーを食わせるプログラムと、クッキーを参照するプログラムは分けて起動すること > > 後これは具体的にどのようにすれば分けて起動できますか? > というよりも起動するのは一つまでする方法しかしらないのですが同時に起動するにはどうしたらできますか? 要するに、「クッキーを書き込むCGI」と「クッキーを読み出すCGI」を別々に作ってブラウザから順にアクセスすればいいのです。 でも、直後に確認したいだけならサーバ側でCGI実行後、クライアントスクリプトを動作させてブラウザ上で表示すれば確認は可能です。 要するに「CGIでクッキー食わせて」から、そのCGIからブラウザに表示させるHTML内に「クッキーを読み込んで表示させるJavaScript」を組み込めばよいのです。 出力するHTMLの例 <html> <head> <meta http-equiv="Content-Language" content="ja"> <meta http-equiv="Content-Type" content="text/html; charset=shift_jis"> <title>クッキー</title> </head> <body> <p>クッキー一覧(以下はブラウザ側で実行される)</p> <script language="JavaScript"> document.write(document.cookie); </script> </body> </html> 長文失礼しました。
その他の回答 (3)
- 神崎 渉瑠(@taloo)
- ベストアンサー率44% (1016/2280)
>クッキーセット直後、同一プロセスからクッキーの環境変数を参照することは無意味です。 通常の処理の流れは以下のようになっています。 クライアント処理(フォームの表示、フォームの送信) ↓ サーバー処理(クッキー発行、この時点でHTTP_COOKIE環境変数は空) ↓ クライアント処理(クッキー受付、保存、HTMLデータ表示) ↓ クライアント処理(ページジャンプ) ↓ サーバー処理(クッキー受信、HTTP_COOKIE環境変数は以前発行したクッキーの内容) 2回目にアクセスした時にしか環境変数からデータを受け取る事は出来ません。 1回目のサーバー処理でクッキーの内容を調べたいのであれば、環境変数ではなく、発行する時の文字列(変数。具体的にはグローバル変数のvalueset)をそのまま参照してください。 (ただしvaluesetにはフォームの内容が期待通り代入されていること。) また、2回目のアクセスでは1回目のプロセスは終了していますから、プロセスのメモリ(共用メモリ?)を参照する事は出来ません。 1回目の処理の内容を確認する必要が有れば、ファイルに保存する等してデータの受け渡しを行わなければなりません。 (いわゆるセッションです。その処理の一部として使用するものがクッキーです。)
- 参考URL:
- http://www.boutell.com/cgic/
補足
ありがとうございます ある程度処理の流れが把握できました。 クッキーを使わないでデータを書き込んでの処理はある程度はできるのですがクッキーを使うと難しいですね クッキーを使わないとデーターが膨大になりすぎるのは困り物なのでクッキーを使っての処理を身に付けないといけませんね。jj
- superside0
- ベストアンサー率64% (461/711)
あっとすいません。訂正というか、補足です。 プログラムでは、 set_cookie(); get_gookie(); の連続にしておいて (1)の初期画面や後続の画面のCGIでは、set_cookie();で次の画面のための処理 (2)の次画面のときは、get_cookie();で前画面からのCookieデータを入手 ということでも、問題なかったです。 ただget_cookie();内で、(1)の時の、フォームからデータがある場合に、 強制的にHTTP_COOKIEからの値で上書きしてしまわないようにしないと、 まずいですね。
お礼
あれから作ってみて完全にバグを取り除けましたので同じ様な疑問をもった人のために書き込んでおきます。 (どうかけばいいか探してもグーグルで検索した時に見つからなかったため) これでちゃんとしたチャットや掲示板が作れる♪ ---ソースの内容--- #include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> char *nameset[3],*valueset[3]; char *nameset2[2],*valueset2[2]; int Deta1(char *a,int b); int Dcd(char *set,int a); void get_Form(void); void set_cookie(void); void get_cookie(void); int hen(char *buf, char *mae, char *ato); void Page(void); void main(void){ printf("Content-type: text/html\n"); get_Form(); if(valueset[0]!=NULL){ set_cookie(); } get_cookie(); printf("\n"); Page(); } int Deta1(char *a,int b){ int i=0,cn=0; if(a[0]==NULL){ return(-1); } nameset[0]=a; while((a[++i]!=NULL)&&(i<b)){ /* 項目の分解 */ if(a[i]=='='){ a[i]=NULL; valueset[cn]=a+i+1; } /* データ項目で分解 */ else if(a[i]=='&'){ a[i]=NULL; cn++; nameset[cn]=a+i+1; } } return cn+1; } int Dcd(char *set,int a){ int i,j; char buf,*tmp; if(a==0){ return -1; } tmp=(char*)malloc(a); for(i=0,j=0;i<a;i++,j++){ if(set[i]=='+'){tmp[j]=' ';continue;} if(set[i]!='%'){tmp[j]=set[i];continue;} if(set[++i]>='A'){buf=set[i]-'A'+10;} else{buf=set[i]-'0';} buf*=16; if(set[++i]>='A'){buf+=set[i]-'A'+10;} else{buf+=set[i]-'0';} tmp[j]=buf; } for(i=0;i<j;i++){ set[i]=tmp[i]; } set[i]='\0'; free(tmp); return 0; } void get_Form(void){ int a=0; char *chr=NULL; if ( getenv("CONTENT_LENGTH")!=NULL ){ a = atoi( getenv("CONTENT_LENGTH") ); } chr=(char *)malloc(a+1); scanf("%s",chr); chr[a] = '\0'; if (a==0){ return; } int deta1=Deta1(chr,a); } void set_cookie(void) { time_t timer; struct tm *tset; char expires[256]; char *name="sskchat"; int kikan=86400*90; char *set[2]; int i; for(i=0;i<2;i++){ set[i]=valueset[i]; } timer = time(NULL); timer += kikan; tset = gmtime(&timer); strftime(expires, 255, "%a, %d-%b-%Y %H:%M:%S GMT", tset); printf("Set-Cookie:%s=name-%s&mail-%s; expires=%s;\n",name,set[0],set[1],expires); } void get_cookie(void){ int i=0,cn=0; int a=NULL; char *b; if((getenv("HTTP_COOKIE"))!=NULL){ a=strlen(getenv("HTTP_COOKIE")); b=getenv("HTTP_COOKIE"); while((b[++i]!=NULL)&&(i<a)){ if(b[i]=='='){ b[i]=NULL; nameset2[0]=b+i+1; } /* 項目の分解*/ if(b[i]=='-'){ b[i]=NULL; valueset2[cn]=b+i+1; } /*データ項目で分解*/ else if(b[i]=='&'){ b[i]=NULL; cn++; nameset2[cn]=b+i+1; } } } for(i=0;i<4;i++){ if(nameset[i]!=NULL){ Dcd(nameset[i],strlen(nameset[i])); } if(valueset[i]!=NULL){ Dcd(valueset[i],strlen(valueset[i])); } if(nameset2[i]!=NULL){ Dcd(nameset2[i],strlen(nameset2[i])); } if(valueset2[i]!=NULL){ Dcd(valueset2[i],strlen(valueset2[i])); } } } void Page(void){ FILE *fp; char buf[200]; char *f1="!name!",*h1=""; char *f2="!mail!",*h2=""; if((valueset[0]==NULL)&&(valueset2[0]!=NULL)){ h1=valueset2[0]; } if(valueset[0]!=NULL){ h1=valueset[0]; } if((valueset[1]==NULL)&&(valueset2[1]!=NULL)){ h2=valueset2[1]; } if(valueset[1]!=NULL){ h2=valueset[1]; } fp = fopen("ren.html", "r+"); while( fgets( buf, 200, fp ) != NULL ){ while(hen(buf, f1, h1)); while(hen(buf, f2, h2)); printf("%s", buf); } fclose(fp); } int hen(char *buf, char *mae, char *ato){ char *nw; size_t zen,go; zen = strlen(mae); go = strlen(ato); if(zen == 0 || (nw = strstr(buf, mae)) == NULL){ return 0; } memmove(nw + go, nw + zen, strlen(buf) - (nw + zen - buf ) + 1); memcpy(nw, ato, go); return 1; } ---ren.htmlの内容--- <html> <head> <title>フォーム</title> </head> <body> <form action="first.exe" method="post"> 名前:<br><input type="text" name="name" size="100" value="!name!"><br><br> メール:<br><input type="text" name="mail" size="100" value="!mail!"><br> 本文:<br><textarea name="text" cols="70" rows="10"></textarea><br><br> <input type="submit" value=" 送 信 "><br> </form> </body> </html>
補足
回答ありがとうございます 最初はsuperside0さんの意見を参考にあれこれいじっていたのですが、うまくいかなかったです。 しかし、今まで私にはない新しいやり方が分かりました。 今後はsuperside0さんのやり方を使う場面も幾つかあるかと思います。 ありがとうございました。
- superside0
- ベストアンサー率64% (461/711)
参照先のソースですが set_cookie(); した直後に get_cookie(); していますが、こういう使い方なら フォームから入手したデータをそのまま使い続ければよいだけなので、 わざわざcookieを経由する意味がないですよね。 フォームデータを、別の画面からのCGIでも参照したいので cookieを使うってことなら、HTMLの画面の推移を考えると 【ブラウザ】初期データ登録の入力フォーム ↓ 【サーバ】フォームデータがCGIにくる。そのCGIが次のHTMLにCookieを埋め込む(1) ↓ 【ブラウザ】HTMLとして入力フォームはないか、ヘッダにCookieデータはある ↓ 【サーバ】 CGIにはフォームデータはこないが、HTTP_COOKIE環境変数から取り出せる(2) という流れでしょうから (1)では フォームデータ解析後に、必要なデータをset_cookie();する (2)では、 (別のフォームデータの解析は必要だが) 。 get_cookie();で(1)を取り出す となるプログラムにして、 プログラムファイル自体を分ける(form action=~を別にする)か 1本のプログラムにまとめるなら if ( 初期データがあるとき またはフォーム上にhiddenでモード指定して条件分岐 ) set_cookie() ; else get_cookie(); のように切り替えるか という形になるべきでしょう。
お礼
---完成した(?)ソース--- #include <stdio.h> #include <stdlib.h>jjjjjjjjjjjjjjjjjjjjjjjjjjjjjj #include <string.h> #include <time.h> char *nameset[3],*valueset[3]; char *nameset2[3],*valueset2[3]; int Deta1(char *a,int b); int Dcd(char *set,int a); void get_Form(void); void set_cookie(void); void get_cookie(void); int hen(char *buf, char *mae, char *ato); void Page(void); void main(void){ printf("Content-type: text/html\n"); get_Form(); set_cookie(); get_cookie(); printf("\n"); Page(); } int Deta1(char *a,int b){ int i=0,cn=0; if(a[0]==NULL){ return(-1); } nameset[0]=a; while((a[++i]!=NULL)&&(i<b)){ /* 項目の分解 */ if(a[i]=='='){ a[i]=NULL; valueset[cn]=a+i+1; } /* データ項目で分解 */ else if(a[i]=='&'){ a[i]=NULL; cn++; nameset[cn]=a+i+1; } } return cn+1; } int Dcd(char *set,int a){ int i,j; char buf,*tmp; if(a==0){ return -1; } tmp=(char*)malloc(a); for(i=0,j=0;i<a;i++,j++){ if(set[i]=='+'){tmp[j]=' ';continue;} if(set[i]!='%'){tmp[j]=set[i];continue;} if(set[++i]>='A'){buf=set[i]-'A'+10;} else{buf=set[i]-'0';} buf*=16; if(set[++i]>='A'){buf+=set[i]-'A'+10;} else{buf+=set[i]-'0';} tmp[j]=buf; } for(i=0;i<j;i++){ set[i]=tmp[i]; } set[i]='\0'; free(tmp); return 0; } void get_Form(void){ int a=0; int i=0; char *chr=NULL; if ( getenv("CONTENT_LENGTH")!=NULL ){ a = atoi( getenv("CONTENT_LENGTH") ); } chr=(char *)malloc(a+1); scanf("%s",chr); chr[a] = '\0'; if (a==0){ return; } int deta1=Deta1(chr,a); } void set_cookie(void) { time_t timer; struct tm *tset; char expires[256]; char *name="sskchat"; int kikan=86400*90; char *set[2]; int i; for(i=0;i<2;i++){ set[i]=valueset[i]; } timer = time(NULL); timer += kikan; tset = gmtime(&timer); strftime(expires, 255, "%a, %d-%b-%Y %H:%M:%S GMT", tset); printf("Set-Cookie:%s=name-%s&mail-%s; expires=%s;\n",name,set[0],set[1],expires); } void get_cookie(void){ int i=0,cn=0; int a=NULL; char *b; if((getenv("HTTP_COOKIE"))!=NULL){ a=strlen(getenv("HTTP_COOKIE")); } if(a==NULL){ } b=getenv("HTTP_COOKIE"); while((b[++i]!=NULL)&&(i<a)){ if(b[i]=='='){ b[i]=NULL; nameset2[0]=b+i+1; } /* 項目の分解*/ if(b[i]=='-'){ b[i]=NULL; valueset2[cn]=b+i+1; } /*データ項目で分解*/ else if(b[i]=='&'){ b[i]=NULL; cn++; nameset2[cn]=b+i+1; } } for(i=0;i<cn+1;i++){ if(nameset[i]!=NULL){ Dcd(nameset[i],strlen(nameset[i])); } if(valueset[i]!=NULL){ Dcd(valueset[i],strlen(valueset[i])); } Dcd(nameset2[i],strlen(nameset2[i])); Dcd(valueset2[i],strlen(valueset2[i])); } } void Page(void){ FILE *fp; char buf[200]; char *f1="!name!",*h1=""; char *f2="!mail!",*h2=""; char *f3="(null)",*h3=""; if((valueset[0]==NULL)&&(valueset2[0]!=NULL)){ h1=valueset2[0]; } if(valueset[0]!=NULL){ h1=valueset[0]; } if((valueset[1]==NULL)&&(valueset2[1]!=NULL)){ h2=valueset2[1]; } if(valueset[1]!=NULL){ h2=valueset[1]; } fp = fopen("ren.html", "r+"); while( fgets( buf, 200, fp ) != NULL ){ while(hen(buf, f1, h1)); while(hen(buf, f2, h2)); while(hen(buf, f3, h3)); printf("%s", buf); } fclose(fp); } int hen(char *buf, char *mae, char *ato){ char *nw; size_t zen,go; zen = strlen(mae); go = strlen(ato); if(zen == 0 || (nw = strstr(buf, mae)) == NULL){ return 0; } memmove(nw + go, nw + zen, strlen(buf) - (nw + zen - buf ) + 1); memcpy(nw, ato, go); return 1; } ---ren.htmlの内容--- <html> <head> <title>フォーム入力内容をクッキーに保存</title> </head> <body> <form action="first.exe" method="post"> 名前:<br><input type="text" name="name" size="100" value="!name!"><br><br> メール:<br><input type="text" name="mail" size="100" value="!mail!"><br><br> 本文:<br><textarea name="text" cols="70" rows="10"></textarea><br><br> <input type="submit" value=" 送 信 "><br> </form> </body> </html> 実はページの最初に2回開くと(NULL)が入力されてしまうバグが出てきてます。 このバグの処理を何とかするためにあれこれ書き直し中
補足
大変詳しくCGIの仕組みを教えてくださりありがとうございました。 おかげでだいぶCGIについて分かってきました。 非常に分かりやすいです。 2つ以上の処理の仕方もやり方がわかりました 教えていただいた <script language="JavaScript"> document.write(document.cookie); </script> このJavaScriptですが、これはすごい今まで出来なかった事が出来る魔法のようだ と思ってこれを使いこなせるようにプログラムを組んでいたら、いつのまにかソースに消えてました。 自分が思ったものがほぼ完成したものを見てびっくりしました。 結果的に、私がやったのは文字の変換の条件式とget_cookieを少し変えただけ…。 完成するまでは教えていただいたJavaScriptを使ってソースを書いたと思ったのですがその記述が一切なくなっているとは本当にびっくりです。 私はJavaScriptに詳しくはないのですがもし教えていただいたJavaScriptを使う事があれば遠慮なく使わせていただきます。 ありがとうございました。