How to make Login Form and validate with PHP MySQL

In this example, We have shown a fully functional login panel in flutter and validate using PHP and MySQL as back end. The panel shows an error message on error and progress indicator on the “login” button click. Here, I have used the REST API to communicate with the Server.

Our Database:

This is the table user list, where the password is md5() encrypted string. The PHP code is given below: test/login.php

<?php 
  $db = "test_db"; //database name
  $dbuser = "root"; //database username
  $dbpassword = "root"; //database password
  $dbhost = "localhost"; //database host

  $return["error"] = false;
  $return["message"] = "";
  $return["success"] = false;

  $link = mysqli_connect($dbhost, $dbuser, $dbpassword, $db);

  if(isset($_POST["username"]) && isset($_POST["password"])){
       //checking if there is POST data

       $username = $_POST["username"];
       $password = $_POST["password"];

       $username = mysqli_real_escape_string($link, $username);
       //escape inverted comma query conflict from string

       $sql = "SELECT * FROM user_list WHERE username = '$username'";
       //building SQL query
       $res = mysqli_query($link, $sql);
       $numrows = mysqli_num_rows($res);
       //check if there is any row
       if($numrows > 0){
           //is there is any data with that username
           $obj = mysqli_fetch_object($res);
           //get row as object
           if(md5($password) == $obj->password){
               $return["success"] = true;
               $return["uid"] = $obj->user_id;
               $return["fullname"] = $obj->fullname;
               $return["address"] = $obj->address;
           }else{
               $return["error"] = true;
               $return["message"] = "Your Password is Incorrect.";
           }
       }else{
           $return["error"] = true;
           $return["message"] = 'No username found.';
       }
  }else{
      $return["error"] = true;
      $return["message"] = 'Send all parameters.';
  }

  mysqli_close($link);

  header('Content-Type: application/json');
  // tell browser that its a json data
  echo json_encode($return);
  //converting array to JSON string
?>

Now in Flutter, you have to add http Flutter package in your dependency by adding the following like in pubspec.yaml

dependencies:
  flutter:
    sdk: flutter
  http: ^0.13.1

Add Internet Permission by adding this line in android/app/src/main/AndroidManifest.xml before <application>

<uses-permission android:name="android.permission.INTERNET"/>

Now, Login Panel Dart Code:

import 'dart:convert';

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:http/http.dart' as http;
//import http package manually

class LoginPage extends StatefulWidget{
  @override
  State<StatefulWidget> createState() {
     return _LoginPage();
  }
}

class _LoginPage extends State<LoginPage>{
  String errormsg;
  bool error, showprogress;
  String username, password;

  var _username = TextEditingController();
  var _password = TextEditingController();

  startLogin() async {
     String apiurl = "http://192.168.0.112/test/login.php"; //api url
     //dont use http://localhost , because emulator don't get that address
     //insted use your local IP address or use live URL
     //hit "ipconfig" in windows or "ip a" in linux to get you local IP
     print(username);

     var response = await http.post(Uri.parse(apiurl), body: {
        'username': username, //get the username text
        'password': password  //get password text
     });
       
     if(response.statusCode == 200){
         var jsondata = json.decode(response.body);
         if(jsondata["error"]){
             setState(() {
                 showprogress = false; //don't show progress indicator
                 error = true;
                 errormsg = jsondata["message"];
             });
         }else{
            if(jsondata["success"]){
               setState(() {
                  error = false;
                  showprogress = false;
               });
               //save the data returned from server
               //and navigate to home page
               String uid = jsondata["uid"];
               String fullname = jsondata["fullname"];
               String address = jsondata["address"];
               print(fullname);
               //user shared preference to save data
            }else{
               showprogress = false; //don't show progress indicator
               error = true;
               errormsg = "Something went wrong.";
            }  
         }
     }else{
        setState(() {
           showprogress = false; //don't show progress indicator
           error = true;
           errormsg = "Error during connecting to server.";
        });
     }
  }

  @override
  void initState() {
     username = "";
     password = "";
     errormsg = "";
     error = false;
     showprogress = false;

     //_username.text = "defaulttext";
     //_password.text = "defaultpassword";
    super.initState();
  }

  @override
  Widget build(BuildContext context) {

    SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle(
       statusBarColor: Colors.transparent
      //color set to transperent or set your own color
    ));
  
    return Scaffold(
        body: SingleChildScrollView( 
            child:Container( 
                constraints: BoxConstraints(
                    minHeight:MediaQuery.of(context).size.height
                    //set minimum height equal to 100% of VH
                ),
                width:MediaQuery.of(context).size.width,
                //make width of outer wrapper to 100%
                decoration:BoxDecoration(
                    gradient: LinearGradient(
                        begin: Alignment.topRight,
                        end: Alignment.bottomLeft,
                        colors: [ Colors.orange,Colors.deepOrangeAccent,
                                  Colors.red, Colors.redAccent,
                        ],
                  ),
                ), //show linear gradient background of page  

                padding: EdgeInsets.all(20),
                child:Column(children:<Widget>[
                     
                     Container(
                        margin: EdgeInsets.only(top:80),
                        child: Text("Sign Into System", style: TextStyle( 
                            color:Colors.white,fontSize: 40, fontWeight: FontWeight.bold
                        ),), //title text
                     ),

                     Container(
                        margin: EdgeInsets.only(top:10),
                        child: Text("Sign In using Email and Password", style: TextStyle( 
                            color:Colors.white,fontSize: 15
                        ),), //subtitle text
                     ),

                     Container( 
                         //show error message here
                         margin: EdgeInsets.only(top:30),
                         padding: EdgeInsets.all(10),
                         child:error? errmsg(errormsg):Container(),
                         //if error == true then show error message
                         //else set empty container as child
                     ),

                     Container( 
                        padding: EdgeInsets.fromLTRB(10,0,10,0),
                        margin: EdgeInsets.only(top:10),
                        child: TextField(
                          controller: _username, //set username controller
                          style:TextStyle(color:Colors.orange[100], fontSize:20),
                          decoration: myInputDecoration(
                              label: "Username",
                              icon: Icons.person,
                          ),
                           onChanged: (value){
                            //set username  text on change
                             username = value;
                          },
                            
                        ),
                     ),

                     Container( 
                        padding: EdgeInsets.all(10),
                        child: TextField(
                          controller: _password, //set password controller
                          style: TextStyle(color:Colors.orange[100], fontSize:20),
                          obscureText: true,
                          decoration: myInputDecoration(
                              label: "Password",
                              icon: Icons.lock,
                          ),
                          onChanged: (value){
                             // change password text
                             password = value;
                          },
                            
                        ),
                     ),

                     Container( 
                       padding: EdgeInsets.all(10),
                       margin: EdgeInsets.only(top:20),
                       child: SizedBox( 
                         height: 60, width: double.infinity,
                         child:RaisedButton(
                                  onPressed: (){
                                     setState(() {
                                        //show progress indicator on click
                                        showprogress = true;
                                     });
                                     startLogin();
                                     
                                  },
                                  child: showprogress? 
                                       SizedBox( 
                                         height:30, width:30,
                                         child: CircularProgressIndicator(
                                           backgroundColor: Colors.orange[100],
                                           valueColor: AlwaysStoppedAnimation<Color>(Colors.deepOrangeAccent),
                                         ),
                                       ):Text("LOGIN NOW", style: TextStyle(fontSize: 20),),
                                       // if showprogress == true then show progress indicator 
                                       // else show "LOGIN NOW" text
                                  colorBrightness: Brightness.dark,
                                  color: Colors.orange,
                                  shape: RoundedRectangleBorder(
                                      borderRadius:BorderRadius.circular(30)
                                      //button corner radius
                                  ),
                         ),
                      ),
                    ),

                     Container( 
                       padding: EdgeInsets.all(10),
                       margin: EdgeInsets.only(top:20),
                       child: InkResponse(
                           onTap:(){
                              //action on tap
                           },
                           child:Text("Forgot Password? Troubleshoot",
                                 style: TextStyle(color:Colors.white, fontSize:18),
                            )
                       ),
                     )
                ]),
            )
        ),
    );
  }

  InputDecoration myInputDecoration({String label, IconData icon}){
     return InputDecoration( 
         hintText: label, //show label as placeholder
         hintStyle: TextStyle(color:Colors.orange[100], fontSize:20), //hint text style
         prefixIcon: Padding(
                         padding: EdgeInsets.only(left:20, right:10),
                         child:Icon(icon, color: Colors.orange[100],)
                         //padding and icon for prefix
                      ),
         
         contentPadding: EdgeInsets.fromLTRB(30, 20, 30, 20),
         enabledBorder: OutlineInputBorder(
            borderRadius: BorderRadius.circular(30),
            borderSide: BorderSide(color:Colors.orange[300], width: 1)
         ), //default border of input

         focusedBorder: OutlineInputBorder(
            borderRadius: BorderRadius.circular(30),
            borderSide: BorderSide(color:Colors.orange[200], width: 1)
         ), //focus border 

         fillColor: Color.fromRGBO(251,140,0, 0.5),
         filled: true, //set true if you want to show input background
     );
  }

  Widget errmsg(String text){
  //error message widget.
        return Container(
            padding: EdgeInsets.all(15.00),
            margin: EdgeInsets.only(bottom: 10.00),
            decoration: BoxDecoration( 
               borderRadius: BorderRadius.circular(30),
               color: Colors.red,
               border: Border.all(color:Colors.red[300], width:2)
            ),
            child: Row(children: <Widget>[
                Container(
                    margin: EdgeInsets.only(right:6.00),
                    child: Icon(Icons.info, color: Colors.white),
                ), // icon for error message
                
                Text(text, style: TextStyle(color: Colors.white, fontSize: 18)),
                //show error message text
            ]),
        );
  }
}

Study the example, and learn how to make the Login Panel and validate the form using PHP and MySQL at the server-side.

5 Comments on this Article

rk reza

signup page code please

11 months ago

sergannn

Amazing - very easy to understand.

How do you think, is it a very out-dated (deprecated) way?

 

1 year ago

Niranjan dahal

Thanks a lot to the point , i already knew php mysqli but don’t have idea to use with flutter , you fully helped me 

2 years ago

Jerico

Why i’m getting this error when i clicked on the button? 

’FormatException (FormatException: Unexpected character (at character 1)’

Help please, thanks!

 

2 years ago

Hari Prasad Chaudhary

Hello Jerico, Please check your API response with POSTMAN, it is due to, there is some error in the PHP code, and your response with error message HTML, so there is an unexpected character due to invalid JSON.

2 years ago


Please Wait...