0

データベースが存在するかどうかを確認するダッシュボード ViewController があり、存在しない場合は、データベースが作成されるログイン ViewController にユーザーを送信します。次に、ユーザーはサインインする必要があり、パスワードとユーザー名が SQLite データベースに保存されます。次に、ダッシュボードの ViewController に送信されます。これに関する問題は、ユーザーがサインインしてダッシュボード ViewController に送り返されると、拒否されてログイン ViewController に送り返されることです。情報がデータベースに保存されていないのか、それとも何が起こっているのかはわかりませんが、これが私のログイン m ファイルです

#import "LoginView.h"
#import "SBJson.h"
#import "SignupView.h"
#import "sqlite3.h"

@interface LoginView ()

@end

@implementation LoginView


@synthesize txtPassword;
@synthesize txtUsername;

-(void)viewDidLoad {
    NSString *docsDir;
    NSArray *dirPaths;

    // Get the documents directory
    dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);

    docsDir = [dirPaths objectAtIndex:0];

    // Build the path to the database file
    databasePath = [[NSString alloc] initWithString: [docsDir stringByAppendingPathComponent: @"username.db"]];

    NSFileManager *filemgr = [NSFileManager defaultManager];

    if ([filemgr fileExistsAtPath: databasePath ] == NO)
    {
        const char *dbpath = [databasePath UTF8String];

        if (sqlite3_open(dbpath, &usernameDB) == SQLITE_OK)
        {
            char *errMsg;
            const char *sql_stmt = "CREATE TABLE IF NOT EXISTS USERNAME (USERNAME TEXT, PASSWORD TEXT)";

            if (sqlite3_exec(usernameDB, sql_stmt, NULL, NULL, &errMsg) != SQLITE_OK)
            {

            }

            sqlite3_close(usernameDB);

        } else {

        }
    }
    [super viewDidLoad];
}

- (void) alertStatus:(NSString *)msg :(NSString *)title
{
    UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:title
                                                        message:msg
                                                       delegate:self
                                              cancelButtonTitle:@"Ok"
                                              otherButtonTitles:nil, nil];

    [alertView show];
}

- (IBAction)signupButton:(id)sender {
    SignupView *myView = [[SignupView alloc] initWithNibName:@"SignupView" bundle:nil];
    [myView setModalPresentationStyle:UIModalPresentationFormSheet]; //you can change the way it is presented
    [myView setModalTransitionStyle:UIModalTransitionStyleCoverVertical]; //you can change the animation
    [self presentViewController:myView animated:YES completion:nil]; //show the modal view

}

- (IBAction)backgroundClicked:(id)sender {
    [txtUsername resignFirstResponder];
    [txtPassword resignFirstResponder];
}

- (IBAction)loginClicked:(id)sender {


    @try {

        if([[txtUsername text] isEqualToString:@""] || [[txtPassword text] isEqualToString:@""] ) {
            [self alertStatus:@"Please enter both Username and Password" :@"Login Failed!"];
        } else {
            NSString *post =[[NSString alloc] initWithFormat:@"username=%@&password=%@",[txtUsername text],[txtPassword text]];
            NSLog(@"PostData: %@",post);

            NSURL *url=[NSURL URLWithString:@"http://example.com/ios_login/index.php"];

            NSData *postData = [post dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];

            NSString *postLength = [NSString stringWithFormat:@"%d", [postData length]];

            NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
            [request setURL:url];
            [request setHTTPMethod:@"POST"];
            [request setValue:postLength forHTTPHeaderField:@"Content-Length"];
            [request setValue:@"application/json" forHTTPHeaderField:@"Accept"];
            [request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
            [request setHTTPBody:postData];

            //[NSURLRequest setAllowsAnyHTTPSCertificate:YES forHost:[url host]];

            NSError *error = [[NSError alloc] init];
            NSHTTPURLResponse *response = nil;
            NSData *urlData=[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];

            NSLog(@"Response code: %d", [response statusCode]);
            if ([response statusCode] >=200 && [response statusCode] <300)
            {
                NSString *responseData = [[NSString alloc]initWithData:urlData encoding:NSUTF8StringEncoding];
                NSLog(@"Response ==> %@", responseData);

                SBJsonParser *jsonParser = [SBJsonParser new];
                NSDictionary *jsonData = (NSDictionary *) [jsonParser objectWithString:responseData error:nil];
                NSLog(@"%@",jsonData);
                NSInteger success = [(NSNumber *) [jsonData objectForKey:@"success"] integerValue];
                NSLog(@"%d",success);
                if(success == 1)
                {
                    [self saveData];

                } else {

                    NSString *error_msg = (NSString *) [jsonData objectForKey:@"error_message"];
                    [self alertStatus:error_msg :@"Login Failed!"];
                }

            } else {
                if (error) NSLog(@"Error: %@", error);
                [self alertStatus:@"Connection Failed" :@"Login Failed!"];
            }
        }
    }
    @catch (NSException * e) {
        NSLog(@"Exception: %@", e);
        [self alertStatus:@"Login Failed." :@"Login Failed!"];
    }
}

-(void)saveData{
    sqlite3_stmt    *statement;

    const char *dbpath = [databasePath UTF8String];

    if (sqlite3_open(dbpath, &usernameDB) == SQLITE_OK)
    {
        NSString *insertSQL = [NSString stringWithFormat: @"INSERT INTO USERNAME (username, password) VALUES (\"%@\", \"%@\")", txtUsername.text, txtPassword.text];

        const char *insert_stmt = [insertSQL UTF8String];

        sqlite3_prepare_v2(usernameDB, insert_stmt, -1, &statement, NULL);
        if (sqlite3_step(statement) == SQLITE_DONE)
        {

        }
        sqlite3_finalize(statement);
        sqlite3_close(usernameDB);

        [self dismissViewControllerAnimated:YES completion:nil];


    }
}

@end

これが私のダッシュボードです M

#import "ViewController.h"
#import "LoginView.h"

@interface ViewController ()

@end

@implementation ViewController
- (void)viewDidAppear:(BOOL)animated {
    [self checkIfLogged];

}

- (void) checkIfLogged
{
    const char *dbpath = [databasePath UTF8String];
    sqlite3_stmt    *statement;

    if (sqlite3_open(dbpath, &usernameDB) == SQLITE_OK) //second if
    {
        NSString *querySQL = [NSString stringWithFormat: @"SELECT * FROM username"];

        const char *query_stmt = [querySQL UTF8String];

        if (sqlite3_prepare_v2(usernameDB, query_stmt, -1, &statement, NULL) == SQLITE_OK)
        {
            if (sqlite3_step(statement) == SQLITE_ROW)
            {//match found



            } else {// match not found

                LoginView *loginView = [[LoginView alloc] initWithNibName:@"LoginView" bundle:nil];
                [loginView setModalPresentationStyle:UIModalPresentationFormSheet];
                [loginView setModalTransitionStyle:UIModalTransitionStyleCoverVertical];
                [self presentViewController:loginView animated:YES completion:nil];



            }//end else
            sqlite3_finalize(statement);


        }//end second if
        else{

            LoginView *loginView = [[LoginView alloc] initWithNibName:@"LoginView" bundle:nil];
            [loginView setModalPresentationStyle:UIModalPresentationFormSheet];
            [loginView setModalTransitionStyle:UIModalTransitionStyleCoverVertical];
            [self presentViewController:loginView animated:YES completion:nil];

        }
        sqlite3_close(usernameDB);

    }//end first IF
   }//end checkIfLogged

@end

情報がデータベースに保存されていないように感じますが、その理由はわかりません。この情報は、saveData() の下のログイン ビューに保存する必要があります。

4

1 に答える 1

0

いくつかの考え:

  1. SQLite 呼び出しのいずれかが失敗した場合、エラーを表示したり、メッセージをログに記録したりしません。したがって、問題を特定することは非常に困難です。SQLite 呼び出しが失敗した場合は、次のようなメッセージをログに記録する必要があります。

    sqlite3_prepare_v2(usernameDB, insert_stmt, -1, &statement, NULL);
    if (sqlite3_step(statement) == SQLITE_DONE)
    {
    
    }
    

    やったほうがいい:

    if (sqlite3_prepare_v2(usernameDB, insert_stmt, -1, &statement, NULL) != SQLITE_OK)
    {
        NSLog(@"%s: insert prepare failed: %s", __FUNCTION__, sqlite3_errmsg(usernameDB));
        sqlite3_close(usernameDB);
        return;
    }
    
    if (sqlite3_step(statement) != SQLITE_DONE)
    {
        NSLog(@"%s: insert step failed: %s", __FUNCTION__, sqlite3_errmsg(usernameDB));
    }
    

    呼び出された SQLite 関数ごとに、この種のログを記録する必要があります。これにより、問題が発生した場合に開発中に通知されるだけでなく、さらに重要なこととして、sqlite3_errmsg関数によって問題の内容が通知されます。

    エラーが発生した場合に報告しない場合、SQLite リターン コードをチェックしてもほとんどメリットがありません。これを行うと、どこが間違っているのかを正確に特定できます。問題はおそらくその時点で自明になるでしょうが、そうでない場合はお知らせください.

  2. この問題を解決したら、ネットワーク リクエストを確認する必要があります。ネットワーク要求は、同期ではなく非同期 (例: sendAsynchronousRequest) で実行する必要があります。メイン キューで同期要求を行うべきではありません。(メイン スレッドでの同期ネットワーク呼び出しの回避を参照してください。)

  3. これも無関係ですが、を使用して SQL を構築するべきではありませんstringWithFormat。パスワードに引用符が含まれている場合はどうなりますか? せいぜい、ユーザーが誤って引用符で何かを入力した場合、SQLite 呼び出しは失敗します。さらに悪いことに、SQL インジェクション攻撃にさらされることになります。

    SQL でプレースホルダーを使用し、値をそれらのプレースホルダーにバインドする必要があり?ます。たとえば、sqlite3_bind_text次のようにします。

    const char *insert_stmt = "INSERT INTO USERNAME (username, password) VALUES (?, ?)";
    
    if (sqlite3_prepare_v2(usernameDB, insert_stmt, -1, &statement, NULL) != SQLITE_OK)
    {
        NSLog(@"%s: insert prepare failed: %s", __FUNCTION__, sqlite3_errmsg(usernameDB));
        sqlite3_close(usernameDB);
        return;
    }
    
    if (sqlite3_bind_text(insert_stmt, 1, [txtUsername.text UTF8String], -1, SQLITE_TRANSIENT) != SQLITE_OK)
    {
        NSLog(@"%s: insert bind user failed: %s", __FUNCTION__, sqlite3_errmsg(usernameDB));
        sqlite3_finalize(statement);
        sqlite3_close(usernameDB);
        return;
    }
    
    if (sqlite3_bind_text(insert_stmt, 2, [txtPassword.text UTF8String], -1, SQLITE_TRANSIENT) != SQLITE_OK)
    {
        NSLog(@"%s: insert bind password failed: %s", __FUNCTION__, sqlite3_errmsg(usernameDB));
        sqlite3_finalize(statement);
        sqlite3_close(usernameDB);
        return;
    }
    
    if (sqlite3_step(statement) != SQLITE_DONE)
    {
        NSLog(@"%s: insert step failed: %s", __FUNCTION__, sqlite3_errmsg(usernameDB));
        sqlite3_close(usernameDB);
        return;
    }
    
    sqlite3_finalize(statement);
    sqlite3_close(usernameDB);
    
  4. また、ネットワーク リクエストで渡すユーザー名とパスワードのパラメータをパーセント エスケープする必要があります。パスワードにアンパサンドまたはプラス記号が含まれている場合はどうなりますか? (アンパサンドは途中でパスワードを終了します。プラスはスペースに変換されます。)

    を使用することを提案する人もstringByAddingPercentEscapesUsingEncodingいますが、実際には を使用するCFURLCreateStringByAddingPercentEscapes必要があり、少し制御できます。したがって、次のようにメソッドを定義できます。

    - (NSString *)stringForPostParameterValue:(NSString *)string
    {
    
        NSString *result = CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault,
                                                                                     (CFStringRef)string,
                                                                                     (CFStringRef)@" ",
                                                                                     (CFStringRef)@";/?:@&=+$,",
                                                                                     kCFStringEncodingUTF8));
        return [result stringByReplacingOccurrencesOfString:@" " withString:@"+"];
    }
    

    したがって、代わりに:

    NSString *post =[[NSString alloc] initWithFormat:@"username=%@&password=%@",[txtUsername text],[txtPassword text]];
    

    次に、次のようにします。

    NSString *post = [NSString stringWithFormat:@"username=%@&password=%@", [self stringForPostParameterValue:[txtUsername text]], [self stringForPostParameterValue:[txtPassword text]]];
    

    +やなどを含むパスワードを使用して現在のコードをテストすると&、上記のようなことをしなければならない理由がわかります。

  5. 明らかに、パスワードを平文で送信/保存するべきではありません。しかし、それはより大きなトピックです。

于 2013-09-30T22:58:46.063 に答える