前回 http://oshiete.goo.ne.jp/qa/7765400.html
からあれこれしてフォームの値をクッキーに保存できるようになったのですが、バグが出てきました。
一、クッキーが存在しないとエラーが出る
ニ、Deta1関数を使って文字列の分解を試みるもうまく分解されない
この2つのバグを解決するにはどうしたら直せますか?
---以下ソース---
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
char *nameset[2],*valueset[2];
char *nameset2[2],*valueset2[2];
int Deta1(char *a,int b);
int Dcd(char *set,int a);
void get_Form(void);
void get_cookie(void);
void set_cookie(void);
int hen(char *buf, char *mae, char *ato);
void Page(int mode);
int main(void) {
char *nameset[2],*valueset[2];
char *nameset2[2],*valueset2[2];
printf("Content-type: text/html\n");
get_Form();
set_cookie();
get_cookie();
printf("\n");
Page(0);
}
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 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++){
Dcd(nameset2[i],strlen(nameset2[i]));
Dcd(valueset2[i],strlen(valueset2[i]));
}
}
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]=NULL;
}
for(i=0;i<2;i++){
set[i]=valueset[i];
}
for(i=0;i<2;i++){
if(set[i]==NULL){
set[i]="no";
}
}
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 Page(int mode){
FILE *fp;
char *f1="!name!",*h1;
char *f2="!mail!",*h2;
if(valueset2[0]==NULL||strcmp("!name!",valueset2[0])==0){
h1="";
}
else{
h1=valueset2[0];
}
if(valueset2[1]==NULL||strcmp("!mail!",valueset2[1])==0){
h2="";
}
else{
h2=valueset2[1];
}
char buf[200];
char set[200];
fp = fopen("ren.html", "r+");
while( fgets( set, 200, fp ) != NULL ){
strcpy(buf,set);
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の内容---
<form action="first.exe" method="post">
名前:<input type="text" name="name" size="100" value="!name!"><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>
No.2ベストアンサー
- 回答日時:
質問1
httpヘッダ出力パート
----------------------------------------
printf("Content-type: text/html\n");
get_Form();
set_cookie();
get_cookie();
printf("\n");
----------------------------------------
の
----------------------------------------
set_cookie();
get_cookie();
----------------------------------------
が"×"です。
クッキーの設定はhttpヘッダから可能ですが、参照は環境変数を介する必要があります(ソースコードもそうなってるはずですが)。
環境変数はクライアントからWebサーバに対して「CGIを介したプログラム」の起動オーダーが発生した際に、その実行プロセスの環境を構成するためにプロセス起動時に作り上げられるものです。(注:CGIはプログラムのことでは有りません。Webを介してプログラムを起動する仕組み→インターフェース:Common Gateway Interface のことです。だから標準入出力機能を持った言語なら何でもOKなのです。)
クッキーセット直後、同一プロセスからクッキーの環境変数を参照することは無意味です。クッキーはブラウザ側に送られても、環境変数はサーバ側にあって自動更新はされません。CGIプロセスの途中でサーバ側からクライアントのデータぶっこ抜き放題ならセキュリティもクソもあったもんじゃないでしょう。
あくまでも「クライアントの指示」でサーバ側のプロセス開始オーダーがあったときのみ必要なデータをクライアント側が送信し、サーバはそこからプロセスに必要なデータから環境変数群を構成してプログラムを開始するのです。
セットしたクッキーを参照したいなら、そのプロセス終了後に新たなプロセス(プログラムを別にする)で参照するしかないでしょう。
要するにクッキーを食わせるプログラムと、クッキーを参照するプログラムは分けて起動すること。
あと「サーバサイドのプログラムまたはプロセス」と「クライアントサイドのプログラムまたはプロセス」の区別をつけて考えることです。
さらに、HTTPをはじめとするTCP/IPについてもプロトコルとは何ぞや程度は・・・。 C/Sやネットプログラミングに限らず言語だけ知ってても仕組みを知らんと実装はなかなか難しいということですね。
質問2
関数「Data1」が挙動不審なので作り直してみました。
nameset[0]に全POSTデータを入れた後、共通のポインタから直にいじり倒しているので最終的にvaluesetの最後と同じになっています。
最適化はしてないので教科書みたいなリスト(しかも古いスタイル)になりますが・・・
---------------------------------------------------------
int Deta1(char *a,int b){
int i,nMax;
char *aTmp[30]; /* とりあえず30個まで耐えられるように */
char *sTmp,*sSTW;
sTmp = a;
i=0;
while((aTmp[i] = strtok(sTmp, "&")) != NULL){
sTmp = NULL;
i++;
}
nMax = i;
for(i=0; i < nMax; i++){
sSTW = aTmp[i];
nameset[i] = strtok(sSTW, "=");
valueset[i] = strtok(NULL, "=");
}
return nMax;
}
---------------------------------------------------------
インデントは全角にしてるのでコピペ時には注意
できれば関数名は別のを考えたほうがいいと思う。代入する変数名とかぶってるし。
あと、評判の悪いstrtok使ってるけど、この処理って基本半角文字だけだから適材適所ってことで
できれば値はエンコードされてるはずだからデコードして出したほうが理にかなってるかも
こんな感じで答えになってるかな・・・。
それにしても、あらためてCの文字列・配列処理は読み書きがめんどくさくて歳を感じてしまいました。
perlで作ったほうが開発効率いいと思う。 正規表現の変態さ加減なんかはもう・・・。
この回答への補足
<<クッキーセット直後、同一プロセスからクッキーの環境変数を参照することは無意味です。クッキーはブラウザ側に送られても、環境変数はサーバ側にあって自動更新はされません。CGIプロセスの途中でサーバ側からクライアントのデータぶっこ抜き放題ならセキュリティもクソもあったもんじゃないでしょう。
あくまでも「クライアントの指示」でサーバ側のプロセス開始オーダーがあったときのみ必要なデータをクライアント側が送信し、サーバはそこからプロセスに必要なデータから環境変数群を構成してプログラムを開始するのです。
セットしたクッキーを参照したいなら、そのプロセス終了後に新たなプロセス(プログラムを別にする)で参照するしかないでしょう。
私のプログラムでおかしなところはまさしくこれですかね
何度かバグらせまくってなんとなく感じてはいましたがはっきり形を教えていらだけましてありがとうございました
問題は方法が分かってもどのように書けばいいか分からない事ですね
<<あと「サーバサイドのプログラムまたはプロセス」と「クライアントサイドのプログラムまたはプロセス」の区別をつけて考えることです。
その区別すら分かっていないので調べる必要がありそうですね
<<科書みたいなリスト(しかも古いスタイル)になりますが・・
教科書みたいな書き方は非常にありがたいです
是非参考にさせていただきます
ありがとうございました
<<あと、評判の悪いstrtok使ってるけど、この処理って基本半角文字だけだから適材適所ってことで
できれば値はエンコードされてるはずだからデコードして出したほうが理にかなってるかも
ああ、なにやら扱いにくいと感じたのはそういう理由ですか
ちゃんと扱えれば動かせるはずだと思って使ってました
<<perlで作ったほうが開発効率いいと思う。 正規表現の変態さ加減なんかはもう・・・
皆さんそういわれますが最終的に戦略シュミレーションのブラウザゲームを作りたいのでperlではちょっと・・・。
といった理由なのでperlは使う気がないのですよ
ごめんなさいね
あれから作ってみて完全にバグを取り除けましたので同じ様な疑問をもった人のために書き込んでおきます。
(どうかけばいいか探してもグーグルで検索した時に見つからなかったため)
これでちゃんとしたチャットや掲示板が作れる♪
---ソースの内容---
#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>
No.1
- 回答日時:
こまかく追い掛けてないけど
・getenvしたポインタの先をそのまま変えちゃって大丈夫?
・mallocとfreeは対になってますか?
・次のものが、 グローバルなものと、main関数ローカルなものがあるけど、Data2関数でグローバルを変えて、それをmain関数内でローカルの方でチェックした、とかないですか?
char *nameset[2],*valueset[2];
char *nameset2[2],*valueset2[2];
あと、エラーにはならないだろうけど、厳密には、NULLと'\0'は違います。
この回答への補足
・getenvしたポインタの先をそのまま変えちゃって大丈夫?
おそらくは・・・・
・mallocとfreeは対になってますか?
なっているはずです(ミスってなければ)
・次のものが、 グローバルなものと、main関数ローカルなものがあるけど、Data2関数でグローバルを変えて、それをmain関数内でローカルの方でチェックした、とかないですか?
char *nameset[2],*valueset[2];
char *nameset2[2],*valueset2[2];
そういえばおかしな処理していました
教えていただきありがとうございました
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
関連するカテゴリからQ&Aを探す
おすすめ情報
- ・漫画をレンタルでお得に読める!
- ・人生のプチ美学を教えてください!!
- ・10秒目をつむったら…
- ・あなたの習慣について教えてください!!
- ・牛、豚、鶏、どれか一つ食べられなくなるとしたら?
- ・【大喜利】【投稿~9/18】 おとぎ話『桃太郎』の知られざるエピソード
- ・街中で見かけて「グッときた人」の思い出
- ・「一気に最後まで読んだ」本、教えて下さい!
- ・幼稚園時代「何組」でしたか?
- ・激凹みから立ち直る方法
- ・1つだけ過去を変えられるとしたら?
- ・【あるあるbot連動企画】あるあるbotに投稿したけど採用されなかったあるある募集
- ・【あるあるbot連動企画】フォロワー20万人のアカウントであなたのあるあるを披露してみませんか?
- ・映画のエンドロール観る派?観ない派?
- ・海外旅行から帰ってきたら、まず何を食べる?
- ・誕生日にもらった意外なもの
- ・天使と悪魔選手権
- ・ちょっと先の未来クイズ第2問
- ・【大喜利】【投稿~9/7】 ロボットの住む世界で流行ってる罰ゲームとは?
- ・推しミネラルウォーターはありますか?
- ・都道府県穴埋めゲーム
- ・この人頭いいなと思ったエピソード
- ・準・究極の選択
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
エクセルで集計したい。
-
cgi アクセス制限 エラー
-
フォームを再送信しますか?
-
古ーくからフリーのtree.cgi掲...
-
-T(汚染モード)でメールが送れ...
-
docomoの構成プロファイルはど...
-
質問ページ(CGI)に行く時にフ...
-
めちゃきれい
-
number 改行が追加できない
-
生成AI画像について
-
3DCG
-
ホームページにメールフォーム...
-
CGIの記述について教えてくださ...
-
CGIの設置が分かりません・・・
-
ホームページにCGIを設置したの...
-
ホームページにCGIを設置したの...
-
サーバーのエラーでおしえてく...
-
ホームページの事でおしえてく...
-
さくらサーバーにcgiフォームを...
-
ホームページでCGIのフォームを...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
tracert ができない原因
-
Perlでuse socketを使用してフ...
-
【CGI】画像の表示の仕方【Mini...
-
c言語 構造体
-
チェックボックスでのor検索
-
ダウンロードをした人の一覧を...
-
日本語文字化け(GETメソッド?)
-
C フォームから受け取った知を...
-
【再】Cookieを使用してフォー...
-
DataGridViewの行取得
-
yoyaku.cgi の改造
-
sendmailのメール送信ができま...
-
CGIでCookie取得
-
perlで書いたcgiでsqliteの使い...
-
【ASP.NET MVC】フォームヘルパ...
-
name[3] = seq + '0';の意味
-
ラジオボタン、チェックボック...
-
CGIで合計を書き出す方法
-
入力フォームに全角・半角スペ...
-
ファイル名変更プログラム
おすすめ情報